Kotlin 在 if else 中检查两次 null

Kotlin check for null twice in if else

我有一个带有变量 datePurchased 的项目,它可以为空。根据购买日期,我生成一个标签。当我检查 datePurchased 是否为 null 时,在 else 分支中我仍然必须检查是否为 null。它说智能转换是不可能的,因为它是可变的 属性.

这是我目前尝试过的方法:

if (datePurchased == null) {
    ""
} else {
    if (datePurchased.isToday()) {//error here
    }
}

    when {
        datePurchased == null    -> {

        }
        datePurchased.isToday() -> {//smart cast bla bla mutable bla bla
        datePurchased?.isToday() -> {//expected Boolean, got Boolean?
        datePurchased?.isToday()?:false -> {//all good, but does not look nice, since datePurchased can't be null here
        }
        else                     -> {

        }
    }

如果您确信没有 datePurchased 变为 null 的数据竞争,则在 else 分支中添加一个非空断言:

if (datePurchased == null) {
    ""
} else {
    datePurchased!!.isToday()
}

或更短更可靠:

datePurchased?.isToday() ?: ""

感谢 marstran,我得到了这样的解决方案:

        return datePurchased?.let {
            when {
                it.isToday()     -> {
                    "Today"
                }
                it.isYesterday() -> {
                    "Yesterday"
                }
                else             -> {
                    dateFormat.format(it)
                }

            }
        } ?: ""
  1. datePurchased 是可变的,这意味着它可以更改。

  2. 您的代码不在 运行 任何类型的同步锁内,这意味着另一个线程可能 运行 并同时修改它。

考虑到这一点,以下是可能的:

if (datePurchased == null) {
    ...
} else {

    // another thread comes in here and changes datePurchased=null

    if (datePurchased.isToday()) { // Null Pointer Exception!
        ...
    }
}

您可能没有线程执行此操作,但编译器不知道。它谨慎行事,说你不能这样做。可能 98% 的情况下它是错误的,但另外 2% 的情况会迫使您考虑您的代码在并发环境中的行为方式。

一种解决方案是简单地使用无法在新线程中更改的本地 val:

val datePurchased = datePurchased

if (datePurchased == null) {
    ...
} else {

    // datePurchased val cannot have been changed, compiler can guarantee safety

    if (datePurchased.isToday()) { 
        ...
    }
}

但最主要的是您现在需要考虑不可变在您的应用上下文中的真正含义,以及您是否真的需要让变量可变。