在 Kotlin 中进行 null 检查的最佳方法?
Best way to null check in Kotlin?
我应该使用双 =
还是三重 =
?
if(a === null) {
//do something
}
或
if(a == null) {
//do something
}
与 'not equals' 类似:
if(a !== null) {
//do something
}
或
if(a != null) {
//do something
}
两种方法生成相同的字节码,因此您可以选择您喜欢的任何一种。
结构等式a == b
被翻译成
a?.equals(b) ?: (b === null)
因此,当与 null
比较时,结构等式 a == null
被转换为引用等式 a === null
。
根据 docs,优化你的代码没有意义,所以你可以使用 a == null
和 a != null
注意 如果变量是可变的 属性,您将无法在 if
语句中将其智能转换为其不可为空的类型(因为该值可能已被另一个线程修改),您必须改用带有 let
的安全调用运算符。
安全呼叫运营商?.
a?.let {
// not null do something
println(it)
println("not null")
}
您可以将它与 Elvis 运算符结合使用。
猫王操作员?:
(我猜是因为问号看起来像猫王的头发)
a ?: println("null")
如果你想运行一段代码
a ?: run {
println("null")
println("The King has left the building")
}
两者结合
a?.let {
println("not null")
println("Wop-bop-a-loom-a-boom-bam-boom")
} ?: run {
println("null")
println("When things go null, don't go with them")
}
查看有用的方法,可能会有用:
/**
* Performs [R] when [T] is not null. Block [R] will have context of [T]
*/
inline fun <T : Any, R> ifNotNull(input: T?, callback: (T) -> R): R? {
return input?.let(callback)
}
/**
* Checking if [T] is not `null` and if its function completes or satisfies to some condition.
*/
inline fun <T: Any> T?.isNotNullAndSatisfies(check: T.() -> Boolean?): Boolean{
return ifNotNull(this) { it.run(check) } ?: false
}
下面是如何使用这些函数的可能示例:
var s: String? = null
// ...
if (s.isNotNullAndSatisfies{ isEmpty() }{
// do something
}
除了@Benito Bertoli,
这个组合实际上不同于if-else
"test" ?. let {
println ( "1. it=$it" )
} ?: let {
println ( "2. it is null!" )
}
结果是:
1. it=test
但是如果:
"test" ?. let {
println ( "1. it=$it" )
null // finally returns null
} ?: let {
println ( "2. it is null!" )
}
结果是:
1. it=test
2. it is null!
此外,如果先使用猫王:
null ?: let {
println ( "1. it is null!" )
} ?. let {
println ( "2. it=$it" )
}
结果是:
1. it is null!
2. it=kotlin.Unit
Kotlin 处理 null 的方式
安全访问操作
val dialog : Dialog? = Dialog()
dialog?.dismiss() // if the dialog will be null,the dismiss call will be omitted
让函数
user?.let {
//Work with non-null user
handleNonNullUser(user)
}
提前退出
fun handleUser(user : User?) {
user ?: return //exit the function if user is null
//Now the compiler knows user is non-null
}
不可变阴影
var user : User? = null
fun handleUser() {
val user = user ?: return //Return if null, otherwise create immutable shadow
//Work with a local, non-null variable named user
}
默认值
fun getUserName(): String {
//If our nullable reference is not null, use it, otherwise use non-null value
return userName ?: "Anonymous"
}
使用 val 代替 var
val
是只读的,var
是可变的。建议尽可能多地使用只读属性,它们是线程安全的。
使用lateinit
有时你不能使用不可变属性。例如,当在 onCreate()
调用中初始化某些 属性 时,它发生在 Android 上。对于这些情况,Kotlin 有一个称为 lateinit
.
的语言特性
private lateinit var mAdapter: RecyclerAdapter<Transaction>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mAdapter = RecyclerAdapter(R.layout.item_transaction)
}
fun updateTransactions() {
mAdapter.notifyDataSetChanged()
}
我应该使用双 =
还是三重 =
?
if(a === null) {
//do something
}
或
if(a == null) {
//do something
}
与 'not equals' 类似:
if(a !== null) {
//do something
}
或
if(a != null) {
//do something
}
两种方法生成相同的字节码,因此您可以选择您喜欢的任何一种。
结构等式a == b
被翻译成
a?.equals(b) ?: (b === null)
因此,当与 null
比较时,结构等式 a == null
被转换为引用等式 a === null
。
根据 docs,优化你的代码没有意义,所以你可以使用 a == null
和 a != null
注意 如果变量是可变的 属性,您将无法在 if
语句中将其智能转换为其不可为空的类型(因为该值可能已被另一个线程修改),您必须改用带有 let
的安全调用运算符。
安全呼叫运营商?.
a?.let {
// not null do something
println(it)
println("not null")
}
您可以将它与 Elvis 运算符结合使用。
猫王操作员?:
(我猜是因为问号看起来像猫王的头发)
a ?: println("null")
如果你想运行一段代码
a ?: run {
println("null")
println("The King has left the building")
}
两者结合
a?.let {
println("not null")
println("Wop-bop-a-loom-a-boom-bam-boom")
} ?: run {
println("null")
println("When things go null, don't go with them")
}
查看有用的方法,可能会有用:
/**
* Performs [R] when [T] is not null. Block [R] will have context of [T]
*/
inline fun <T : Any, R> ifNotNull(input: T?, callback: (T) -> R): R? {
return input?.let(callback)
}
/**
* Checking if [T] is not `null` and if its function completes or satisfies to some condition.
*/
inline fun <T: Any> T?.isNotNullAndSatisfies(check: T.() -> Boolean?): Boolean{
return ifNotNull(this) { it.run(check) } ?: false
}
下面是如何使用这些函数的可能示例:
var s: String? = null
// ...
if (s.isNotNullAndSatisfies{ isEmpty() }{
// do something
}
除了@Benito Bertoli,
这个组合实际上不同于if-else
"test" ?. let {
println ( "1. it=$it" )
} ?: let {
println ( "2. it is null!" )
}
结果是:
1. it=test
但是如果:
"test" ?. let {
println ( "1. it=$it" )
null // finally returns null
} ?: let {
println ( "2. it is null!" )
}
结果是:
1. it=test
2. it is null!
此外,如果先使用猫王:
null ?: let {
println ( "1. it is null!" )
} ?. let {
println ( "2. it=$it" )
}
结果是:
1. it is null!
2. it=kotlin.Unit
Kotlin 处理 null 的方式
安全访问操作
val dialog : Dialog? = Dialog()
dialog?.dismiss() // if the dialog will be null,the dismiss call will be omitted
让函数
user?.let {
//Work with non-null user
handleNonNullUser(user)
}
提前退出
fun handleUser(user : User?) {
user ?: return //exit the function if user is null
//Now the compiler knows user is non-null
}
不可变阴影
var user : User? = null
fun handleUser() {
val user = user ?: return //Return if null, otherwise create immutable shadow
//Work with a local, non-null variable named user
}
默认值
fun getUserName(): String {
//If our nullable reference is not null, use it, otherwise use non-null value
return userName ?: "Anonymous"
}
使用 val 代替 var
val
是只读的,var
是可变的。建议尽可能多地使用只读属性,它们是线程安全的。
使用lateinit
有时你不能使用不可变属性。例如,当在 onCreate()
调用中初始化某些 属性 时,它发生在 Android 上。对于这些情况,Kotlin 有一个称为 lateinit
.
private lateinit var mAdapter: RecyclerAdapter<Transaction>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mAdapter = RecyclerAdapter(R.layout.item_transaction)
}
fun updateTransactions() {
mAdapter.notifyDataSetChanged()
}