AbstractList unsupportedOperationException 在 List 上调用 .sort



我正在使用 Collections.sort(( 对列表进行排序,它似乎正在以各种方式对其进行测试。 不过,我的一些用户正在崩溃。

Caused by java.lang.UnsupportedOperationException
    java.util.AbstractList.set (AbstractList.java:681)
    java.util.AbstractList$FullListIterator.set (AbstractList.java:143)
    java.util.Collections.sort (Collections.java:1909)
    com.myapp.MyFragment.myMethod (MyFragment.java:225)

但是,我所做的只是尝试对列表进行排序

private void myMethod(List<MyThing> myThings) {
    Collections.sort(myList, (thing1, thing2) -> Long.compare(thing2.getLongValue(), thing1.getLongValue()));

我注意到这在Android 8及更高版本上不会发生。它只发生在 5.0 - 7.1 上

该列表实例化为 ArrayList,填充,并设置为类实例的成员作为泛型列表。 然后,此对象与事件总线一起发布。 然后使用 Kotlin 的mapsortedByDescending函数对列表进行映射和排序。 然后将映射和排序的列表传递给myMethod()

这个 Kotlin 扩展正在生成传递给此方法的列表:

fun List<MyThing>.mapAndSort(context: Context): List<MyThing> {
    return mapNotNull {
        when (it.type) {
            type -> it.getTyped(context) //all of these return polymorphic MyThings
            anotherType -> it.getAnotherTyped(context)
            someOtherType -> it.getSomeOtherTyped(context)
            yetAnotherType -> it.getYetAnotherType(context)
            yetOneMoreType -> it.getYetOneMoreType(context)
            finallyLastTyope -> it.getFinallyLastType(context)
            else -> null
        }
    }.sortedByDescending { it.longValue }
}

到目前为止,我已经看到这个列表是一个java.util.Arrays$ArrayListkotlin.collections.EmptyList

我认为这与 EventBus 有关,但可能是 Kotlin 传递了 Kotlin 集合列表类型。 有谁确切知道发生了什么?

Collections.sort是一个就地列表突变操作。如果你打算在你的 Java 方法中调用它,只在那里传递一个静态已知的列表,它是 Kotlin 中的MutableList

如果你有一个未知可变性的List,你可以通过调用它.toMutableList()扩展函数来获取MutableList

如果用 Java 编写myMethod不是主要的,你可以用 Kotlin 中的调用替换它list.sortedByDescending { it.longValue }那么你就不需要先将该列表转换为可变列表。事实上,这就是mapAndSort方法最终的作用,所以看起来没有必要再次排序。

这次崩溃的根源似乎是,在内部,如果Iterable的大小为 0 或 1,Iterable<T>.sortedWith(由 Iterable<T>.sortedByDescending 使用(会创建一个新列表:

public fun <T> Iterable<T>.sortedWith(comparator: Comparator<in T>): List<T> {
    if (this is Collection) {
       if (size <= 1) return this.toList() // <-- HERE
       @Suppress("UNCHECKED_CAST")
       return (toTypedArray<Any?>() as Array<T>).apply { sortWith(comparator) }.asList()
    }
    return toMutableList().apply { sortWith(comparator) }
}

函数toList()依次调用listOf

public fun <T> Iterable<T>.toList(): List<T> {
    if (this is Collection) {
        return when (size) {
            0 -> emptyList()
            1 -> listOf(if (this is List) get(0) else iterator().next())
            else -> this.toMutableList()
        }
    }
    return this.toMutableList().optimizeReadOnlyList()
}

这反过来将解析为一个EmptyList(可以安全排序,因为它是空的(或一个不实现setSingletonList from AbstractList

以下是一些证据:

https://try.kotlinlang.org/#/UserProjects/s3j6g8476h8047vvvsjuvletlr/rjlkkn3n6117c1aagja8dr1h67

我们可能会遇到错误,或者至少是改进,因为如果它是 List 类型,sortedWith可能会返回this

public fun <T> Iterable<T>.sortedWith(comparator: Comparator<in T>): List<T> {
    if (this is Collection) {
       if (size <= 1) return if(this is List<T>) this else this.toList()
       @Suppress("UNCHECKED_CAST")
       return (toTypedArray<Any?>() as Array<T>).apply { sortWith(comparator) }.asList()
    }
    return toMutableList().apply { sortWith(comparator) }
}

最新更新