【问题标题】:Why getting a type mismatch when using Collections.Sort method with a List<String?>?为什么在使用带有 List<String?> 的 Collections.Sort 方法时会出现类型不匹配?
【发布时间】:2020-11-18 22:59:47
【问题描述】:

为什么以下代码无法编译并出现错误: “类型不匹配:推断的类型是 String?但 Comparable!是预期的 '!' 是什么意思在括号之后?以及为什么它说推断类型是 String 如果它完全是 Mu​​tableList? ?

代码:

private fun createAllGamesList(gamesPerCountriesMap: MutableMap<String?, MutableMap<Long, MutableList<AllScoresGameObj>>>?)
            :List<BaseDataItem>
    {
        var countriesNameSet =  gamesPerCountriesMap?.keys
        var countriesNameList = countriesNameSet?.toMutableList()
        Collections.sort(countriesNameList)

        countriesNameList?.let{

        }


    } 

【问题讨论】:

    标签: android kotlin


    【解决方案1】:

    只是想指出在 Kotlin 中使用 Java 类 Collections 有点不鼓励,因为 Kotlin 标准库具有内置函数,可以以更适合 Kotlin 样式语法的方式执行相同的任务,具有更好的可空性处理,并且在使用内联 lambda 时性能会更高。

    例如,如果使用 Kotlin 的 sort()sortedBy(),就不会遇到奇怪的类型 Comparable&lt;String?&gt;!。类型后面的 ! 符号意味着它可能是可空的,也可能不是因为 Java 代码没有指定任何一种方式。

    在 Kotlin 中,如果 MutableList 具有 Comparable 类型,您可以直接在您的 MutableList(它是一个扩展函数)上调用 sort()。您仍然会遇到String? 不是Comparable&lt;String?&gt; 的问题,但是您可以使用compareBythenBy 进行自定义排序以创建比较器:

    countriesNameList.sortedWith(
        compareBy<String?> { it ?: "" } // lambda returns String, which is Comparable
            .thenBy { it == null } // Sort between empty Strings and null values by returning a Boolean (another Comparable
    )
    

    【讨论】:

    • 谢谢。所以如果是 '!' 这意味着它可能是可空的或不可空的,但如果它是 '?' 这意味着它绝对可以为空?有什么区别?在这两种情况下,我都需要将其视为可为空的?
    • ?意味着它迫使您将其视为可为空的,并且!意味着它不会强迫你。
    • 谢谢。是否将其视为在 Kotlin 代码中检查 null 的可空方法?
    • 这意味着你不能在没有 nullsafe 操作符的情况下调用函数(除非它是一个可以为空接收器的扩展函数)。 ! 的原因是 Java 没有内置的可空性,因此编译器无法真正猜测该类型是否可以为空。在 Java 中,通常在 Javadocs 中声明参数或返回类型是否允许为 null,因此如果 Javadocs 说它不会为 null,您可以安全地省略 null 检查,并且 Kotlin 编译器不会警告您。如果您检查 null,它也不会警告您进行不必要的 null 检查。
    【解决方案2】:

    问题在于countriesNameList 是一个可以为空的字符串列表。也就是说,它的类型是MutableList&lt;String?&gt;,而不是MutableList&lt;String&gt;

    Collections.sort() 要求集合的类型实现Comparable&lt;T&gt;,但String? 没有实现Comparable&lt;String?&gt;。我想这是因为null 值在String? 元素的自然顺序中的位置并不明显。

    使用以下代码很容易观察到:

    val list: MutableList<String?> = mutableListOf("hello", "world")
    Collections.sort(list)
    

    如果我将类型规范更改为不包含?,问题就会消失:

    val list: MutableList<String> = mutableListOf("hello", "world")
    Collections.sort(list)
    

    您可以通过提供自己的比较器来解决此问题:

    Collections.sort(countriesNameList) { lhs, rhs -> customCompare(lhs, rhs) }
    
    private fun customCompare(lhs: String?, rhs: String?): Int = when {
        lhs == null && rhs == null -> 0
        lhs == null -> 1
        rhs == null -> -1
        else -> lhs.compareTo(rhs)
    }
    

    【讨论】:

    • 这个版本的customCompare() 会将空值推到列表的末尾。如果您希望它们位于列表的前面,请在中间两种情况下交换1-1
    • 谢谢。但我想改进我理解编辑器/编译器的方式。您能否解释一下这是什么意思:“推断类型是 String?但是 Comparable!”他是否忽略了它是 MutableList 的事实? ! 是什么意思?我知道它与平台类型有关,但不明白这是什么意思?似乎实际问题和编译器警告何时来自两个不同的世界......此外,我很乐意解释为什么这两种中间情况会影响 null 在排序中的位置。是因为插入排序的工作方式?
    猜你喜欢
    • 2017-01-06
    • 2021-12-18
    • 1970-01-01
    • 2017-02-09
    • 2020-01-12
    • 1970-01-01
    • 2015-12-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多