如何避免!!在 returns 不可为 null 的函数中

How to avoid !! in a function which returns a non-nullable

在下面的示例中,函数应该 return 一个非空数据。 由于数据在过程中可能会发生变化,所以需要是var,而且只能是nullable开头。

我不能使用 lateinit 因为 if (d == null) 的第一个调用会抛出。

处理后它会被分配一个非空数据,但是return必须使用!!(双爆炸或非空断言运算符)。

避免 !! 的最佳方法是什么?

fun testGetLowest (dataArray: List<Data>) : Data {
   var d: Data? = null
   for (i in dataArray.indecs) {

       if (d == null) {// first run
           d = dataArray[i]
       } else if {
           d.level < dataArray[i].level
           d = dataArray[i]
       }
    }
    return d!!
}

如何进行相同的检查,并覆盖空壳

fun testGetLowest(dataArray: List<Data>) 
    = dataArray.minBy { it.level } ?: throw AssertionError("List was empty")

这使用 ?: 运算符获取最小值,或者如果最小值为空(列表为空)则抛出错误。

即使将其转换为 Option,您仍然必须处理 dataArray 为空且值 returned 未定义的情况。

如果你想让它成为一个完整的函数而不是抛出异常,你可以 return 一个 Option<Data> 而不是 Data 这样空的情况下 dataArray 将 return 一个 None 并留给调用者处理如何处理悲伤路径。

如果您不喜欢 !!,请为其提供默认值。您会意识到,如果列表不为空,您只能提供默认值,但是,正如您所说,已知该列表是非空的。这个故事的好处是类型系统不跟踪列表大小,所以当你说 dataArray[0] 时,它会相信你的话。

fun testGetLowest(dataArray: List<Data>) : Data {
    var d: Data = dataArray[0]
    for (i in 1 until dataArray.size) {
        if (d.level < dataArray[i].level) {
            d = dataArray[i]
        }
    }
    return d
}

通常,您可以而且应该依靠编译器来推断可空性。这并不总是可能的,并且在人为的示例中,如果内部循环运行但一旦 d 为非空。如果 dataArray 至少有一名成员,这肯定会发生。

利用这些知识,您可以使用 require to check the arguments (for at least one member of the array) and checkNotNull 稍微重构代码,将 dataArray 的状态断言为 post 条件。

fun testGetLowest (dataArray: List<Data>) : Data {
   require(dataArray.size > 0, { "Expected dataArray to have size of at least 1: $dataArray")
   var d: Data? = null
   for (i in dataArray.indecs) {

       if (d == null) {// first run
           d = dataArray[i]
       } else if {
           d.level < dataArray[i].level
           d = dataArray[i]
       }
    }
    return checkNotNull(d, { "Expected d to be non-null through dataArray having at least one element and d being assigned in first iteration of loop" })
}

请记住,您可以 return checkNotNull(和类似运算符)的结果:

val checkedD = checkNotNull(d)

请参阅 Google Guava 的 Preconditions 了解类似内容。

接受的答案完全没问题,但只是提一下通过更改代码中的一行来解决问题的另一种方法:return d ?: dataArray[0]