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

stszievb  于 2023-05-23  发布在  Kotlin
关注(0)|答案(6)|浏览(309)

我应该使用双倍=还是三倍=

if(a === null)  {
//do something
}

if(a == null)  {
//do something
}

类似于“不相等”:

if(a !== null)  {
//do something
}

if(a != null)  {
//do something
}
mkshixfv

mkshixfv1#

结构等式a == b被转换为

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

因此,当与null进行比较时,结构等式a == null被转换为引用等式a === null
根据docs,优化代码没有意义,因此可以使用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")
}
iovurdzv

iovurdzv2#

Kotlin处理null的方式

安全访问操作

val dialog: Dialog? = Dialog()
dialog?.dismiss()  // If the dialog is null, the dismiss call will be omitted

Let函数

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"
}

使用瓦尔而不是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()
}
qltillow

qltillow3#

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

u3r8eeie

u3r8eeie4#

添加到@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
balp4ylt

balp4ylt5#

查看有用的方法,它可能是有用的:

/**
 * 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
}
gt0wga4j

gt0wga4j6#

我想回应@Benito Bertoli和@BingLi224的答案,并提供imho正确的解决方案。
问题是使用let,因为let的结果是它的最后一个表达式。你只想传递和传入它的相同的东西,所以also是一个更好的解决方案。同时,在使用elvis操作符后,let无法使用,因为没有对象可以调用扩展函数,所以我使用run(函数版)。更多关于scope functions official documentation
与使用if/when相比,另一个缺点是不能将其用作表达式,因此我不建议使用它:-)
最终代码:

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

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

null?.also {
    println("1. it is null!")
} ?: run {
    println("2. it is null")
}

null?.also {
    println("1. it is null!")
    null
} ?: run {
    println("2. it is null")
}

和输出:

1. it=test
1. it=test
2. it is null
2. it is null

相关问题