问题
I'm sorting a List using Collections.sort(), which seems to be working every way I can test it. Some of my users are crashing though.
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)
But, all I'm doing is trying to sort a List
private void myMethod(List<MyThing> myThings) {
    Collections.sort(myList, (thing1, thing2) -> Long.compare(thing2.getLongValue(), thing1.getLongValue()));
I'm noticing this doesnt happen on Android 8 and above. Its only happening on 5.0 - 7.1
The list is instantiated as an ArrayList, populated, and set as a member of an instance of a class as a generic list.  This object is then posted with EventBus.  The list is then mapped and sorted using Kotlin's map and sortedByDescending functions.  The mapped and sorted list is then passed to myMethod()
This Kotlin extension is generating the list passed to this method:
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 }
}
So far I've seen this list be a java.util.Arrays$ArrayList, and kotlin.collections.EmptyList. 
I'm thinking this has something to do with EventBus, but may be Kotlin passing a Kotlin collections list type. Does anyone know exactly what's going on?
回答1:
The source of this crash seems to be that, internally, Iterable<T>.sortedWith (which is used by Iterable<T>.sortedByDescending) creates a new list if the size of the Iterable is 0 or 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) }
}
The function toList() in turn will call 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()
}
Which in turn will resolve into either an EmptyList (which is safe to sort since it's empty) or a SingletonList which doesn't implement set from AbstractList
Here is some evidence:
https://try.kotlinlang.org/#/UserProjects/s3j6g8476h8047vvvsjuvletlr/rjlkkn3n6117c1aagja8dr1h67
We could potentially have a bug or, at least, an improvement since sortedWith could return this if it's of type List:
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) }
}
回答2:
Collections.sort is an in-place list mutating operation. If you're going to invoke it in your Java method, do only pass a list there that is statically known to be a MutableList in Kotlin.
If you have a List of unknown mutability, you can get a MutableList from it by calling .toMutableList() extension function on it.
And if it's not principal to you to have myMethod written in Java, you can replace it with list.sortedByDescending { it.longValue } call in Kotlin, then you wouldn't need to turn that list into a mutable list first. In fact that's what mapAndSort method does in the end, so it looks like there's no need to sort it again. 
来源:https://stackoverflow.com/questions/55802573/abstractlist-unsupportedoperationexception-when-calling-sort-on-a-list