简体   繁体   English

如何在 Kotlin 中检查 List 是否包含 null?

[英]How to check whether a List contains null in Kotlin?

I'm having trouble understanding why我无法理解为什么

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

causes the compilation error ...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.导致编译错误...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. ...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. . .

If I use outputStreams.contains(null as OutputStream)) the compilation succeeds, but Main(LinkedList<OutputStream>()) fails at runtime due to如果我使用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)

which leaves me with no other approach for keeping the code as close to the original Java as possible which is my intend as well as understanding this issue as it is rather than searching for a workaround.这让我没有其他方法可以使代码尽可能接近原始 Java,这是我的意图以及理解这个问题,而不是寻找解决方法。

For the compiler, the parameter outputStreams cannot contain null as its type is List<OutputStream> as opposed to List<OutputStream?> . 对于编译器,参数outputStreams不能包含null因为它的类型是List<OutputStream>而不是List<OutputStream?> The type system does not expect null to be inside this list, thus no need to check it. 类型系统不期望null在此列表中,因此无需检查它。

On the other hand , IF that parameter actually could contain null (since it comes from a Java caller) you should mark it as nullable explicitly: List<OutputStream?> 另一方面如果该参数实际上可以包含null (因为它来自Java调用者),您应该将其明确标记为可为空: List<OutputStream?>

I belive that the answer is List<OutputStream?> . 我相信答案是List<OutputStream?> ? will make your list can contain null . 将使您的列表可以包含null Check the doc: enter link description here 检查doc: 在此处输入链接描述

filterNotNull() method can filter out all null objects from the collection so you could use the code below. filterNotNull()方法可以过滤掉集合中的所有空对象,以便您可以使用下面的代码。 Obviously, you need to inform the compiler that objects in the collection are nullable. 显然,您需要通知编译器集合中的对象可以为空。 I changed the OutputStream type to String for easier testing. 我将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
}
 }

A second approach would be to use let T.let(block: (T) -> R): R where you would accept the nullable object, but then you would have to check whether there is any "null" string and react accordingly. 第二种方法是使用let T.let(block:(T) - > R):R你可以接受可空对象,但是你必须检查是否有任何“null”字符串并做出相应的反应。

    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)
}

}

If you are "confident" that the object parameter in the constructor should be a collection of non-null objects, then you can remove ? 如果您“确信”构造函数中的object参数应该是非null对象的集合,那么您可以删除吗? However, the nullable check on the List collection must be done by an object initialising Main class, so you would basically move the responsibility of catching NullPointerException to someone else. 但是,List集合上的可空检查必须由初始化Main类的对象完成,因此您基本上将捕获NullPointerException的责任移交给其他人。

I don't have enough rep to comment on ToraCode's answer, but further to what they have said, I expect the type of LinkedList() is actually List<OutputStream!> meaning that the type is either List<OutputStream> or List<OutputStream?> 我没有足够的代表来评论ToraCode的答案,但是根据他们的说法,我希望LinkedList()的类型实际上是List<OutputStream!>这意味着该类型是List<OutputStream>List<OutputStream?>

Types with ! 类型! after them are platform types. 之后是平台类型。 So List<OutputStream!> would mean "Java List of OutputStream may be nullable or not" We simply have no way of knowing. 所以List<OutputStream!>意味着“OutputStream的Java List可以是可空的”我们根本无法知道。

I think it is safest to follow ToraCode's recommendation, use List<OutputStream?> and check for nulls. 我认为遵循ToraCode的建议是最安全的,使用List<OutputStream?>并检查空值。

For more information on the interoperability of kotlin see: https://kotlinlang.org/docs/reference/java-interop.html#notation-for-platform-types 有关kotlin互操作性的更多信息,请参阅: https ://kotlinlang.org/docs/reference/java-interop.html#notation-for-platform-types

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM