Сортировка объектов по их строковому полю, включая языковые символы

Я хотел бы отсортировать список своих объектов по полю их строкового имени. Но в этих именах есть некоторые полированные символы, и из-за этого сортировка некорректна. Я провел небольшое исследование проблемы и выяснил, что мне следует использовать что-то вроде:

Collections.sort(myList, Collator.getInstance());

Но проблема в том, что это работает только тогда, когда я пытаюсь отсортировать список строк. Когда я пытаюсь отсортировать список своих объектов, я получаю java.lang.ClassCastException. Как я могу отсортировать список моих объектов в алфавитном порядке на польском языке?

Мой объект выглядит примерно так:

public class MyObject implements Comparable<MyObject>{
     private String name;
     ...

     @Override
    public int compareTo(@NonNull MyObject object) {
        return name.compareTo(object.getName());
    }

А сейчас пытаюсь отсортировать вот так:

List<MyObject> myList = DataProvider.getInstance().getListOfObjects();    
Collections.sort(myList, Collator.getInstance());

Может ли name содержать также непольские символы, такие как немецкий, французский? Если да, то как бы вы их заказать?

Pshemo 04.09.2018 17:01
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
2
1
80
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Я считаю, что в Collatorдокументация есть некоторая двусмысленность.

Collator - это Comparator<Object>, но он действительно нацелен на выполнение

locale-sensitive String comparison (emphasis mine).

Вы можете лучше увидеть это в документация конкретной реализации Collator#compare:

This implementation merely returns compare((String)o1, (String)o2).


ClassCastException, который вы получаете, вероятно, связан с тем, что очевидно, что MyObject не является String.


Я бы попытался перенести использование Collator в вашу фактическую реализацию compareTo:

Collections.sort(myList);

... и в вашей реализации compareTo:

Collator.getInstance().compare(name, object.getName());

Обратите внимание, что идиома Collator.getInstance() использует Locale по умолчанию.

Следовательно, если вы планируете использовать несколько Locale для сравнения ваших объектов в зависимости от контекста, вам может быть лучше выполнить сортировку с помощью специального Comparator, который позволяет вводить Locale и использовать Collator под капотом.

Я реализовал сортировку так, как вы предложили, используя коллатор внутри реализации compareTo. И теперь я получаю ошибку: java.lang.IllegalArgumentException: Comparison method violates its general contract!

matip 06.09.2018 14:09

@matip не произошел в моей репликации (с вашими открытыми условиями), однако я не аннотировал параметр как @NonNull. Если вы не добавили дополнительный код по сравнению с вашим вопросом, попробуйте избавиться от него, так как это может нарушить подпись переопределения, насколько мне известно. Фактически, вы должны обрабатывать случаи null в теле compareTo.

Mena 06.09.2018 14:11

Хорошо, что я обрабатываю нулевые случаи внутри тела compareTo. Только когда имена не равны нулю, я использую Collator.getInstance().compare

matip 06.09.2018 14:29

@matip, вероятно, что-то не так с вашей реализацией, но об этом трудно догадаться без реального кода.

Mena 06.09.2018 14:30

Мне удалось заставить это работать. Когда я обрабатывал нулевой регистр в методе compareTo, я возвращал 0. Теперь я возвращаю 1 в таких случаях, и все работает.

matip 06.09.2018 15:29

@matip, который это объясняет, да. 0 будет означать, что объекты должны считаться равными, что не имело бы смысла, если бы один из них был null, а тот, который выполнял compareTo, явно не был :)

Mena 06.09.2018 15:34

Collator используется для сравнения строк, вы можете извлечь имя и передать их в Collator:

myList.sort((o1, o2) -> Collator.getInstance().compare(o1.getName(), o2.getName()));

Другие вопросы по теме