如何在Kotlin中检查列表是否包含空值?

时间:2018-10-09 10:45:03

标签: java collections kotlin

我无法理解为什么

class Main {
    private val outputStreams: List<OutputStream>

    @JvmOverloads constructor(outputStreams: List<OutputStream> = LinkedList()) {
        if(outputStreams.contains(null)) {
            throw IllegalArgumentException("outputStreams mustn't contain null")
        }
        this.outputStreams = outputStreams
    }
}

导致编译错误...Main.kt:[12,26] Type inference failed. The value of the type parameter T should be mentioned in input types (argument types, receiver type or expected type). Try to specify it explicitly.

如果我使用outputStreams.contains(null as OutputStream)),则编译成功,但由于运行原因,Main(LinkedList<OutputStream>())在运行时失败了

kotlin.TypeCastException: null cannot be cast to non-null type java.io.OutputStream
    at kotlinn.collection.contains.nulll.check.Main.<init>(Main.kt:12)
    at kotlinn.collection.contains.nulll.check.MainTest.testInit(MainTest.kt:13)

这使我没有其他方法可以使代码尽可能地接近原始Java,这是我的意图,同时也是要真正理解此问题,而不是寻找解决方法。

4 个答案:

答案 0 :(得分:4)

对于编译器,参数outputStreams不能包含null,因为其类型为List<OutputStream>,而不是List<OutputStream?>。类型系统不希望null包含在此列表中,因此无需检查它。

另一方面如果该参数实际上可能包含null(由于它来自Java调用程序),则应将其明确标记为可为空: List<OutputStream?>

答案 1 :(得分:3)

我相信答案是List<OutputStream?>?将使您的列表可以包含null。 检查文档:enter link description here

答案 2 :(得分:1)

filterNotNull()方法可以从集合中过滤掉所有空对象,因此您可以使用下面的代码。 显然,您需要通知编译器集合中的对象可以为空。 为了方便测试,我将OutputStream类型更改为String。

    class Main{
private val outputStreams: List<String?>

@JvmOverloads constructor(outputStreams: List<String?> = LinkedList()) {

    if(outputStreams.filterNotNull().size < outputStreams.size) {
        throw IllegalArgumentException("outputStreams mustn't contain null")
    }
    this.outputStreams = outputStreams
}

fun getOutputStream(): List<String?>{
    return outputStreams
}
 }

第二种方法是在可以接受可为空的对象的地方使用let T.let(block:(T)-> R):R,但是随后您必须检查是否存在任何“空”字符串,并且做出相应的反应。

    class Main{
lateinit var outputStreams: List<String?>

@JvmOverloads constructor(outputStreams: List<String?> = LinkedList()) {

    outputStreams.let {
        this.outputStreams = outputStreams
    }

}

fun getOutputStream(): List<String?>{
    return outputStreams
}
}

    fun main(args: Array<String>) {
val outputStreamWithNull: List<String?> = listOf("alpha", "beta", null, "omega")
val mainA = Main(outputStreamWithNull)


mainA.getOutputStream().forEach {
    println(it)
}

}

如果您“确信”构造函数中的object参数应该是非null对象的集合,则可以删除? 但是,必须通过初始化Main类的对象来完成对List集合的可空检查,因此您基本上会将捕获NullPointerException的职责转移给其他人。

答案 3 :(得分:0)

我没有足够的代表评论ToraCode的答案,但按照他们所说的,我希望LinkedList()的类型实际上是List<OutputStream!>,这意味着该类型可以是{{1 }}或List<OutputStream>

带有!的类型它们是平台类型。因此List<OutputStream?>的意思是“ OutputStream的Java列表可能为空或不能为空”。我们根本无法知道。

我认为遵循ToraCode的建议,使用List<OutputStream!>并检查是否为空是最安全的。

有关kotlin互操作性的更多信息,请参见:https://kotlinlang.org/docs/reference/java-interop.html#notation-for-platform-types