AbstractList UnsupportedOperationException при вызове .sort в Списке - PullRequest
0 голосов
/ 23 апреля 2019

Я сортирую Список с помощью 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.Затем список отображается и сортируется с использованием функций map и sortedByDescending от Kotlin.Затем сопоставленный и отсортированный список передается на 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$ArrayList и kotlin.collections.EmptyList.

Я думаю, что это как-то связано с EventBus, но, возможно, Kotlin передает тип списка коллекций Kotlin.Кто-нибудь точно знает, что происходит?

Ответы [ 2 ]

5 голосов
/ 23 апреля 2019

Collections.sort - операция изменения списка на месте.Если вы собираетесь вызывать его в своем Java-методе, передайте только тот список, который в Kotlin известен как MutableList.

Если у вас List неизвестной изменчивости, выможно получить MutableList из него, вызвав для него функцию расширения .toMutableList().

И если для вас не принципиально, чтобы myMethod был написан на Java, вы можете заменить его на вызов list.sortedByDescending { it.longValue } вKotlin, тогда тебе не нужно будет сначала превращать этот список в изменяемый список.Фактически это то, что метод mapAndSort делает в конце, так что, похоже, нет необходимости его снова сортировать.

1 голос
/ 23 апреля 2019

Источник этого сбоя, по-видимому, заключается в том, что внутренне Iterable<T>.sortedWith (который используется Iterable<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

Вот некоторые доказательства:

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

У нас может быть ошибка или, по крайней мере, улучшение, поскольку sortedWith может вернуть this, если оно имеет тип 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) }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...