如何避免 Kotlin 字段中的冗余空检查(FindBugs 警告)

How to avoid Redundant null check (FindBugs warning) in Kotlin field

我在 Kotlin 的 class 中有一个归档 bytes

var bytes: ByteArray? = null
    get() = when {
        field != null -> Arrays.copyOf(field, field!!.size)
        else -> field
    }
    set(value) {
        field = when {
            value != null -> Arrays.copyOf(value, value.size)
            else -> null
        }
    }

为什么在第 3 行必须有一个 !! 运算符代表 field

!! 思路显示:

Smart cast to 'ByteArray' is impossible, because 'field' is a mutable property that could have been changed by this time

条件(field != null) 确保字段在 if 正文(右侧)中为空。或不?或者它可以同时重新分配给 null ?这怎么可能?

使用上面的代码 FindBugs 警告:

Redundant nullcheck of com.xy.Some.bytes which is known to be null in com.xy.Some.getBytes()

This method contains a redundant check of a known null value against the constant null.

http://findbugs.sourceforge.net/bugDescriptions.html#RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE

您不能使用可为空的可变属性进行智能转换,因为在这段代码中:

 if (nullableMutableProp != null) {
   doSomethingWith(nullableMutableProp)
 }

在第 1 行和第 2 行之间,其他代码可以将值更改为 null。

您可以分配给本地 val 并智能丢弃:

get() {
  val local = field
  return when {
    local != null -> Arrays.copyOf(local, local.size)
    else -> local
  }
}

bytes 是一个 var,它是可变的,可以在 null 检查后更改(可能在其他线程上)。你不能保证 bytes 是非空的,所以在这里使用 !! 是不安全的。

Official explanation:

Note that smart casts do not work when the compiler cannot guarantee that the variable cannot change between the check and the usage. More specifically, smart casts are applicable according to the following rules:

  • val local variables - always;
  • val properties - if the property is private or internal or the check is performed in the same module where the property is declared. Smart casts aren't applicable to open properties or properties that have custom getters;
  • var local variables - if the variable is not modified between the check and the usage and is not captured in a lambda that modifies it;
  • var properties - never (because the variable can be modified at any time by other code).

解决方法之一是使用 let:

get() = field?.let { Arrays.copyOf(it, it.size) } ?: field

建议阅读: