【问题标题】:Best way to null check in Kotlin?在 Kotlin 中进行空检查的最佳方法?
【发布时间】:2016-09-10 22:09:24
【问题描述】:

我应该使用双重=,还是三重=

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

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

同样适用于“不等于”:

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

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

【问题讨论】:

标签: kotlin kotlin-null-safety


【解决方案1】:

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

【讨论】:

  • 如果我理解正确,那么他要求在 Kotlin 中检查 null 的最佳方法,而不是哪种方法生成最佳字节码。@BenitoBertoli 答案看起来很有希望,它减少了样板代码
【解决方案2】:

结构相等 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")
}

【讨论】:

  • 为什么不使用if 进行空检查? a?.let{} ?: run{} 仅在极少数情况下适用,否则不习惯
  • @voddan 我并不是建议不要将 if 用于null 检查,而是列出其他可行的选项。虽然我不确定run 是否有某种性能损失。我会更新我的答案以使其更清楚。
  • @voddan 如果avar,则使用a?.let{} ?: run{} 保证它将在整个范围内正确绑定在let 中。如果aval,则没有区别。
  • @madeinqc 如果 a 是 val,那么使用 let 是不同的,而且很糟糕。我发现这篇文章非常擅长解释它 - Kotlin: Don’t just use LET for null check.
  • @voddan 我是 Kotlin 的新手。请您解释一下或提供一个 URL,说明这不是惯用的吗?
【解决方案3】:

检查有用的方法,它可能有用:

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

【讨论】:

    【解决方案4】:

    除了@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】:

      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 是可变的。建议尽可能多地使用只读属性,它们是线程安全的。

      使用后期初始化

      有时你不能使用不可变的属性。例如,当在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()
      }
      

      【讨论】:

      • 我将最后一个称为“默认值”(不是 elvis),因为其中 3/4 使用的是 elvis。
      • @AjahnCharles 说得通))
      • 这是垃圾,任何现代语言都可以比这更好地处理可选项。对程序员来说,这更像是一件苦差事而不是好处。
      猜你喜欢
      • 2011-04-30
      • 1970-01-01
      • 2013-06-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-04
      • 1970-01-01
      相关资源
      最近更新 更多