在Kotlin中,处理可空值的惯用方式是什么,引用或转换它们
如果我有一个可空typesXyz?  ,我想引用它或将其转换为不可为空的typesXyz 。  Kotlin这样做的习惯用法是什么? 
例如,这个代码是错误的:
 val something: Xyz? = createPossiblyNullXyz() something.foo() // Error: "Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type Xyz?" 
但是,如果我先检查null是允许的,为什么呢?
 val something: Xyz? = createPossiblyNullXyz() if (something != null) { something.foo() } 
 假如我知道它确实从不为null ,我该如何将值更改或视为非null而不要求if检查? 例如,在这里我从地图中检索一个值,我可以保证存在,并且get()的结果不为null 。 但是我有一个错误: 
 val map = mapOf("a" to 65,"b" to 66,"c" to 67) val something = map.get("a") something.toLong() // Error: "Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type Int?" 
 方法get()认为有可能该项目丢失,并返回typesInt?  。 因此,强制价值types不能为空的最好方法是什么? 
注意: 这个问题是由作者故意写的和回答的( 自我回答的问题 ),所以对于常见的Kotlin话题的习惯性的回答是在SO中。 此外,为了澄清一些真正的古老的答案写为科特林的阿尔法,是不是今天的Kotlin准确。
首先,你应该阅读所有关于Kotlin全面涵盖案例的Null Safety 。
 在Kotlin中,如果不能确定它是否为null ( 在条件中检查为null ),或者断言它肯定不是null的,  确定操作员 ,用?.访问它?.  安全调用 ,或者最后使用?: Elvis运算符给出可能为null的默认值。 
在你的第一个案例中,你可以根据代码的意图select其中的一个,而且都是惯用的,但是有不同的结果:
 val something: Xyz? = createPossiblyNullXyz() // access it as non-null asserting that with a sure call val result1 = something!!.foo() // access it only if it is not null using safe operator, // returning null otherwise val result2 = something?.foo() // access it only if it is not null using safe operator, // otherwise a default value using the elvis operator val result3 = something?.foo() ?: differentValue // null check it with `if` expression and then use the value, // similar to result3 but for more complex cases harder to do in one expression val result4 = if (something != null) { something.foo() } else { ... differentValue } // null check it with `if` statement doing a different action if (something != null) { something.foo() } else { someOtherAction() } 
对于“为什么在空值检查时工作”,请阅读下面关于智能转换的背景信息。
  对于你在 Map 问题中的第二种情况 ,如果你作为一个开发人员肯定结果永远不是null ,请使用!! 肯定算作一个断言: 
 val map = mapOf("a" to 65,"b" to 66,"c" to 67) val something = map.get("a")!! something.toLong() // now valid 
 或者在另一种情况下,当映射COULD返回一个null值,但是你可以提供一个默认值,那么Map本身就有一个getOrElse方法 : 
 val map = mapOf("a" to 65,"b" to 66,"c" to 67) val something = map.getOrElse("z") { 0 } // provide default value in lambda something.toLong() // now valid 
背景信息:
注意: 在下面的示例中,我使用显式types来使行为清晰。 通过types推断,通常可以省略局部variables和私有成员的types。
 更多关于的!! 确定运营商 
  !! 运算符声明该值不为null或抛出NPE。 这应该用在开发者保证值永远不会为null 。 把它看作是一个断言,然后是一个聪明的演员 。 
 val possibleXyz: Xyz? = ... // assert it is not null, but if it is throw an exception: val surelyXyz: Xyz = possibleXyz!! // same thing but access members after the assertion is made: possibleXyz!!.foo() 
阅读更多: ! 确定运营商
 有关null检查和智能转换的更多信息 
 如果使用null检查保护对可空types的访问,编译器将智能地将语句体内的值转换为非空值。 有一些复杂的stream程,这不可能发生,但一般情况下工作正常。 
 val possibleXyz: Xyz? = ... if (possibleXyz != null) { // allowed to reference members: possiblyXyz.foo() // or also assign as non-nullable type: val surelyXyz: Xyz = possibleXyz } 
 或者如果你做的is检查一个不可为空的types: 
 if (possibleXyz is Xyz) { // allowed to reference members: possiblyXyz.foo() } 
对于'when'expression式也是安全的:
 when (possibleXyz) { null -> doSomething() else -> possibleXyz.foo() } // or when (possibleXyz) { is Xyz -> possibleXyz.foo() is Alpha -> possibleXyz.dominate() is Fish -> possibleXyz.swim() } 
 有些事情不允许null检查智能强制转换为以后使用的variables。 上面的例子使用了一个本地variables,这个variables在应用程序的stream程中决不可能发生变化,无论val或var这个variables是否没有机会变为null 。 但是,在其他情况下,编译器不能保证stream分析,这将是一个错误: 
 var nullableInt: Int? = ... public fun foo() { if (nullableInt != null) { // Error: "Smart cast to 'kotlin.Int' is impossible, because 'nullableInt' is a mutable property that could have been changed by this time" val nonNullableInt: Int = nullableInt } } 
 variablesnullableInt的生命周期不是完全可见的,可以从其他线程分配, null检查不能被智能转换为不可空值。 有关解决方法,请参阅下面的“安全调用”主题。 
 另一个智能强制转换不能被信任的情况是具有自定义getter的对象的val属性。 在这种情况下,编译器不知道该variables的值是什么,因此你会得到一个错误信息: 
 class MyThing { val possibleXyz: Xyz? get() { ... } } // now when referencing this class... val thing = MyThing() if (thing.possibleXyz != null) { // error: "Kotlin: Smart cast to 'kotlin.Int' is impossible, because 'px' is a property that has open or custom getter" thing.possiblyXyz.foo() } 
阅读更多: 检查条件为空
 更多关于?. 安全呼叫操作员 
如果左边的值为空,则安全调用操作符返回null,否则继续计算右边的expression式。
 val possibleXyz: Xyz? = makeMeSomethingButMaybeNullable() // "answer" will be null if any step of the chain is null val answer = possibleXyz?.foo()?.goo()?.boo() 
 另一个例子,你想要迭代一个列表,但只有当不为null而不是空时,安全调用操作符才会派上用场: 
 val things: List? = makeMeAListOrDont() things?.forEach { // this loops only if not null (due to safe call) nor empty (0 items loop 0 times): } 
 在上面的例子中,我们有一个情况,我们做了一个if检查,但有机会另一个线程突变的价值,因此没有聪明的演员 。 我们可以改变这个例子,使用安全调用算子和let函数来解决这个问题: 
 var possibleXyz: Xyz? = 1 public fun foo() { possibleXyz?.let { value -> // only called if not null, and the value is captured by the lambda val surelyXyz: Xyz = value } } 
阅读更多: 安全通话
 更多关于?:猫王操作员 
 当运算符左侧的expression式为null时,Elvis运算符允许您提供另一个值: 
 val surelyXyz: Xyz = makeXyzOrNull() ?: DefaultXyz() 
 它也有一些创造性的用途,例如,当某些东西为null时抛出exception: 
 val currentUser = session.user ?: throw Http401Error("Unauthorized") 
或者从函数提前返回:
 fun foo(key: String): Int { val startingCode: String = codes.findKey(key) ?: return 0 // ... return endingValue } 
阅读更多: 猫王操作员
具有相关函数的空操作符
Kotlin stdlib具有一系列function,可以很好地与上述操作员一起工作。 例如:
 // use ?.let() to change a not null value, and ?: to provide a default val something = possibleNull?.let { it.transform() } ?: defaultSomething // use ?.apply() to operate further on a value that is not null possibleNull?.apply { func1() func2() } // use .takeIf or .takeUnless to turn a value null if it meets a predicate val something = name.takeIf { it.isNotBlank() } ?: defaultName val something = name.takeUnless { it.isBlank() } ?: defaultName 
相关话题
 在Kotlin中,大多数应用程序试图避免null值,但并不总是可能的。 有时候null是非常有意义的。 一些指导思想: 
- 
在某些情况下,它保证不同的返回types,包括方法调用的状态和成功的结果。 像Result这样的库给你一个成功或失败的结果types,也可以分支你的代码。 Kotlin的Promise库叫Kovenant,它的承诺forms也一样。 
- 
对于集合来说,返回types总是返回一个空集合,而不是 null,除非你需要第三个“不存在”状态。 Kotlin具有帮助函数,如emptyList()或emptySet()来创build这些空值。
- 
当使用返回一个默认值或替代值的可为空值的方法时,使用Elvis操作符提供一个默认值。 在 Map的情况下使用getOrElse(),它允许生成一个默认值,而不是Map方法get(),它返回一个可为空的值。 相同的getOrPut()
- 
当从Kotlin不确定Java代码的可空性的Java重写方法时,您总是可以放弃 ?如果您确定签名和function应该是什么,那么您可以忽略它。 因此,你重写的方法是更安全的。 在Kotlin中实现Java接口也是一样的,把它改为可以被认为是有效的。
- 
查看已经可以帮助的函数,比如对于 String?.isNullOrEmpty()和String?.isNullOrBlank(),它们可以安全地操作一个可为null的值,并按照您的期望进行操作。 实际上,您可以添加自己的扩展来填充标准库中的任何空缺。
- 
断言函数,如标准库中的 checkNotNull()和requireNotNull()。
- 
像 filterNotNull()从集合中删除filterNotNull()帮助器函数,或者listOfNotNull()用于从可能的null值返回零或单个项目列表。
- 
还有一个安全(可为空)的转换操作符 ,如果不可能,则允许非空types的转换返回null。 但是我没有一个有效的用例来解决上面提到的其他方法。 
以前的答案是难以遵循的,但是这里有一个简单快捷的方法:
 val something: Xyz = createPossiblyNullXyz() ?: throw RuntimeError("no it shouldn't be null") something.foo() 
如果它真的不是空的,这个exception就不会发生,但如果它永远是你会发现什么地方出了问题。