@gsaw

Как правильно настроить типизацию Comporator класса?

Здрастье и извиняюсь за стыдный вопрос. Но никак не могу побороть типизацию у java.util.Comparator. У меня есть record с вложенным record. И надо отсортировать список. Для этого создал такой класс WorkerComparator

record Fio(String name, String surname) {};
record Worker(int id, Fio fio, Integer salary, LocalDateTime hiredOn) {};

class WorkerComparator implements Comparator<Worker> {
    private static final Comparator safeCompare = Comparator.nullsFirst(Comparator.naturalOrder());

    @Override
    public int compare(Worker o1, Worker o2) {

        return Objects.compare(o1, o2,
                Comparator.comparing(key -> ((Worker)key).fio().surname(), safeCompare)
                        .thenComparing(key -> ((Worker)key).fio().name(), safeCompare)
                        .thenComparing(key -> ((Worker)key).salary(), safeCompare)
                        .thenComparing(key -> ((Worker)key).hiredOn(), safeCompare));
    }
}


Это работает, но мне не нравится, что надо явно указывать каст к Worker

((Worker)key)

Да и вообще выходит кучка ворнингов типа

"Unchecked call to 'thenComparing(Function<? super T, ? extends U>, Comparator<? super U>)' as a member of raw type 'java.util.Comparator' "

Я по всякому пытался подставлять типы в угловатых скобочках. Типа

return Objects.compare(o1, o2,
                Comparator.<Worker, String>comparing(key -> key.fio().surname(), safeCompare)
                        .<String>thenComparing(key -> ((Worker)key).fio().name(), safeCompare)
                        .<Integer>thenComparing(key -> ((Worker)key).salary(), safeCompare)
                        .<LocalDateTime>thenComparing(key -> ((Worker)key).hiredOn(), safeCompare));


Но это работает только для comparing(), потому как там можно указать тип Worker, но у последующих методов thenComparing в определении нету места для объекта, только для конечного типа.

default <U> Comparator<T> thenComparing(
            Function<? super T, ? extends U> keyExtractor,
            Comparator<? super U> keyComparator)
    {
        return thenComparing(comparing(keyExtractor, keyComparator));
    }


Может я не так пользуюсь comparing и thenComparing цепочкой, хоть это и работает?
  • Вопрос задан
  • 75 просмотров
Решения вопроса 1
@gsaw Автор вопроса
Все дело было в "safeCompare". Он вносил сумятицу. Без него все выходит норм

return Objects.compare(o1, o2,
                Comparator.<Worker, String>comparing(key -> key.fio().surname())
                        .thenComparing(key -> key.fio().name())
                        .thenComparing(Worker::salary)
                        .thenComparing(Worker::hiredOn));


Но так как у меня null значения, приходится делать так. Лучшего ничего не придумал.

class WorkerComparator implements Comparator<Worker> {
    final static Comparator<String> safeString = Comparator.nullsFirst(Comparator.naturalOrder());
    final static Comparator<Integer> safeInteger = Comparator.nullsFirst(Comparator.naturalOrder());
    final static Comparator<LocalDateTime> safeLocalDateTime = Comparator.nullsFirst(Comparator.naturalOrder());

    @Override
    public int compare(Worker o1, Worker o2) {

        return Objects.compare(o1, o2,
                Comparator.<Worker, String>comparing(key -> key.fio().surname(), safeString)
                        .thenComparing(key -> key.fio().name(), safeString)
                        .thenComparing(Worker::salary, safeInteger)
                        .thenComparing(Worker::hiredOn, safeLocalDateTime));
    }
}


Сделал под разные типы свой Comparator
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
al_gon
@al_gon
Как вариант:

public static void main(String[] args) {
		Comparator<Worker> c1 =  Comparator.comparing(key -> key.fio().surname(), Comparator.nullsFirst(Comparator.naturalOrder()));
		Comparator<Worker> c2 = Comparator.comparing(key -> key.fio().name(),Comparator.nullsFirst(Comparator.naturalOrder()));
		Comparator<Worker> c3 = Comparator.comparing(Worker::salary, Comparator.nullsFirst(Comparator.naturalOrder()));
		Comparator<Worker> c4 = Comparator.comparing(Worker::hiredOn, Comparator.nullsFirst(Comparator.naturalOrder()));
		List<Worker> workers = new ArrayList<>(List.of(
				new Worker(1, new Fio(null, null), 50, null),
		        new Worker(1, new Fio(null, null), 15, null),
				new Worker(1, new Fio("Bob",null ), 15, null)
		));
		workers.sort(c1.thenComparing(c2).thenComparing(c3).thenComparing(c4));
		workers.forEach(System.out::println);
	}


UPDATE:

public static void main(String[] args) {
Comparator<Fio> cFio1 = Comparator.comparing(Fio::name, Comparator.nullsFirst(String::compareTo));
Comparator<Fio> cFio2 = Comparator.comparing(Fio::surname,Comparator.nullsFirst(String::compareTo));

Comparator<Worker> cFioCommon =  Comparator.comparing(Worker::fio,Comparator.nullsFirst(cFio1).thenComparing(Comparator.nullsFirst(cFio2)));

Comparator<Worker> c3 = Comparator.comparing(Worker::salary, Comparator.nullsFirst(Comparator.naturalOrder()));
Comparator<Worker> c4 = Comparator.comparing(Worker::hiredOn, Comparator.nullsFirst(Comparator.naturalOrder()));

List<Worker> workers = new ArrayList<>(List.of(
	new Worker(1, new Fio(null, null), 50, null),
	new Worker(1,null, 50, null),
	new Worker(1, new Fio("Bob", null), 15, null),
	new Worker(1, new Fio("Alice",null ), 15, null)
		));
workers.add(null);
workers.sort(Comparator.nullsFirst(cFioCommon.thenComparing(c3).thenComparing(c4)));
workers.forEach(System.out::println);
}
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы