把"运行时炸"提前到"编译期报错" - Kotlin 怎么干掉了 NullPointerException。
x?.method():如果 x 是 null,整个表达式返回 null,**不抛异常**。x ?: default:如果 x 为 null,用右边的默认值。x!!.method():强制当成非空,**为 null 时立即抛 NPE**。obj as? String:转不成返回 null,不抛 ClassCastException。x?.let { it.foo() }:x 非空时进入块,块内 it 是非空类型。下面每个组合,你预测结果是什么?点击"显示答案"对照。
name = null + name?.lengthname = null + name!!.lengthname = null + name?.length ?: 0name = "hi" + name!!.length调整每一层的状态("有值"/"null"),看 Kotlin 怎么短路。
Java 不区分可空/非空(除非加注解),Kotlin 推断出的类型是 String!("既能当 String 又能当 String? 用")。这是 Kotlin 唯一不能保证空安全的地方。
// Java
public class JavaApi {
public String getName() {
// 可能返回 null !
return Math.random() > 0.5 ? "Alice" : null;
}
}
// Kotlin 推断为 String!
val name = api.getName()
// 编译能过!但 50% 概率运行时炸
println(name.length)
// → java.lang.NullPointerException
// at MainKt.main()
// 明确声明类型
val name: String? = api.getName()
// 编译器强制你处理 null
val len = name?.length ?: 0
println("长度 = $len")
// 或用 let
name?.let { println("got: $it") }
val name: String? = ...@Nullable/@NotNull 注解,Kotlin 会识别(IntelliJ、JSR-305、JetBrains 等都支持)