在Kotlin中进行空值检查的最佳方法?


Answers:


62

两种方法都生成相同的字节码,因此您可以选择自己喜欢的任何一种。


2
如果我理解正确的话那么他是要求最好的方式在科特林检查空,没有哪种方法最好生成字节码@ BenitoBertoli答案看起来很有希望,这是减少样板代码
IMGS

148

结构平等a == b被翻译成

a?.equals(b) ?: (b === null)

因此,在进行比较时null,将结构相等a == null转换为参照相等a === null

根据文档,优化代码没有任何意义,因此您可以使用a == nulla != 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")
}

1
为什么不使用ifnull检查?a?.let{} ?: run{}仅在极少数情况下适用,否则不是惯用语言
voddan

2
@voddan我不是建议不要使用if作为null支票,而是列出其他可行的选择。尽管我不确定是否run会有某种性能损失。我将更新答案以使其更加清晰。
贝尼托·贝托利

1
@voddan如果a为a var,则使用a?.let{} ?: run{}保证将其let在整个范围内正确绑定。如果aval,则没有区别。
madeinqc

1
@madeinqc如果a是a val,则使用let是不同的,这很不好。我发现这篇文章很好地解释了它-Kotlin:不要只使用LET进行null检查
苏菲安

34

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

有时您不能使用不可变属性。例如,它在Android上在onCreate()调用中初始化某些属性时发生。对于这些情况,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()
}

我将最后一个称为“默认值”(不是elvis),因为其中3/4使用的是elvis。
AjahnCharles

@AjahnCharles有道理))
Levon Petrosyan

8

除了@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!

另外,如果首先使用Elvis:

null ?: let {
    println ( "1. it is null!" )
} ?. let {
    println ( "2. it=$it" )
}

结果是:

1. it is null!
2. it=kotlin.Unit

5

检查出有用的方法,这可能是有用的:

/**
 * 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
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.