在列表上调用.sort时AbstractList UnsupportedOperationException

时间:2019-04-23 00:06:27

标签: java android exception kotlin collections

我正在使用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,被填充,并被设置为作为通用列表的类的实例的成员。然后将该对象与EventBus一起发布。然后使用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收藏列表类型。有谁确切地知道发生了什么事?

2 个答案:

答案 0 :(得分:5)

Collections.sort是就地列表变异操作。如果要在Java方法中调用它,请仅传递在Kotlin中静态已知为MutableList的列表。

如果您有List未知的可变性,则可以通过在其上调用MutableList扩展函数来从中获得.toMutableList()

如果用Java编写myMethod对您来说不是主要的,您可以在Kotlin中用list.sortedByDescending { it.longValue }调用替换它,那么您无需先将该列表变成可变列表。实际上,这就是mapAndSort方法的最终结果,因此看起来好像不需要再次对其进行排序。

答案 1 :(得分:1)

此崩溃的原因似乎是,内部Iterable<T>.sortedWithIterable<T>.sortedByDescending使用)Iterable的大小为0或1时创建了一个新列表:

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(由于为空,因此可以安全地进行排序)或SingletonList,它不能从set实现AbstractList < / p>

以下是一些证据:

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

由于sortedWith的类型为thisList可能返回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) } } ,因此我们可能会遇到错误或至少有所改进:

Shared Sub New()
    'Await setAllAccountsAsync()
    SetAllAccounts()
End Sub