Как правильно спроектировать компаратор?

 
 
 
Сообщения:35
Я обучаюсь паралельно в одной онлайн-школе разработке на Java. Вчера выполнял задание, где пришлось написать компаратор для сортировки. Вот так выглядить сортировка у меня:

        Arrays.sort(this.students, (st1, st2) -> {
            if (st1 == null ^ st2 == null) {
                return (st1 == null) ? -1 : 1;
            }

            if (st1 == null && st2 == null) {
                return 0;
            }

            return st1.getSurname().compareToIgnoreCase(st2.getSurname());
        });


Я реализовал функцию сортировки sort() без анонимного класса или передачи компаратора по ссылке, а реализовав его функционально.
Интересно, мнение профессионалов на сколько актуален такой подход. Имею ввиду, стоит ли писать компараторы отдельно и потом их передавать туда, где они нужны или лучше писать функционально как у меня?
Так же интересен момент проверки передаваемых аргументов на null. Я проверил параметры прямо в теле реализации. Преподаватель говорит, что есть смысл вынести проверку из тела. Но его вариант мне вообще не понравился. Какой-то не вариант..
У него есть интерфейс для проверка параметров на null:

public interface CheckNull {
    public int NOT_NULL = 7;

    public static int checkNull(Object obj1, Object obj2) {
        if (obj1 == null && obj2 != null) {
            return -1;
        }
        if (obj1 != null && obj2 == null) {
            return 1;
        }
        if (obj1 == null && obj2 == null) {
            return 0;
        }
        return NOT_NULL;
    }
}


И вот сама проверка:

        Arrays.sort(this.students, (obj1, obj2) -> CheckNull.checkNull(obj1, obj2) != CheckNull.NOT_NULL ? CheckNull.checkNull(obj1, obj2) :
        obj1.getSurname().compareTo(obj2.getSurname()));


Только что-то мне его способ не нравиться. По моему слишком он не вариантовый. В общем-то, очень интересно услышать мнение более опытных программистов по реализации подобных задач.
 
 
Сообщения:402
hoz:
Интересно, мнение профессионалов на сколько актуален такой подход.

это делается по необходимости

hoz:
Так же интересен момент проверки передаваемых аргументов на null.

следует задаться вопросом зачем вам null элементы в массиве ?
 
 
Сообщения:35
keekkenen:

это делается по необходимости

В смысле?

keekkenen:

следует задаться вопросом зачем вам null элементы в массиве ?

Ну возник вариант того, что могут быть пустые элементы массива. Разве такого не бывает?
 
 
Сообщения:402
hoz:
В смысле?

если компаратор реализует частный случай, то он может описываться любым способом, если он переиспользуется, то очевидно, что это отдельный объект (в виде кода)
hoz:
Ну возник вариант того, что могут быть пустые элементы массива. Разве такого не бывает?

бывает, но нельзя такой массив гонять по методам - это пример плохой архитектуры, какой смысл если в массиве пара объектов и десяток наллов ?
ну, отсортировали мы их, но наллы-то все равно лишние, разве нет ?
 
 
Сообщения:35
keekkenen:

если компаратор реализует частный случай, то он может описываться любым способом, если он переиспользуется, то очевидно, что это отдельный объект (в виде кода)

Это понятно. В любом случае, если даже не выносить компаратор, то это можно сделать позже, когда он будет нужен уже не в одном месте.

keekkenen:

бывает, но нельзя такой массив гонять по методам - это пример плохой архитектуры, какой смысл если в массиве пара объектов и десяток наллов ?
ну, отсортировали мы их, но наллы-то все равно лишние, разве нет ?

Логично. Но у меня было такое задание для практики. В моём случае варианте использования интерфейса адекватный или может быть какое-то более изящное решение? Я об интерфейсе проверки на ноль..
 
 
Сообщения:402
hoz:
об интерфейсе проверки на ноль..

для общего случая нормальное решение, единственно, непонятно зачем там NOT_NULL, существующие объекты должны сортироваться по каким-то своим атрибутам (одному или нескольким), а так они никак не сортируются для пар существующих объектов
 
 
Сообщения:35
keekkenen:
hoz:
об интерфейсе проверки на ноль..

для общего случая нормальное решение, единственно, непонятно зачем там NOT_NULL, существующие объекты должны сортироваться по каким-то своим атрибутам (одному или нескольким), а так они никак не сортируются для пар существующих объектов

Как я понял, это возвращает факт того ни 1 из сравниваемых объектов не null. Но как-то оно всё-равно криво..

Я вот так придумал сегодня:

public interface CheckNull {
    public int NOT_NULL = 7;

    public static int checkNull(Object obj1, Object obj2) {
        if (obj1 == null ^ obj2 == null) {
            return (obj1 == null) ? -1 : 1;
        }
        if (obj1 == null && obj2 == null) {
            return 0;
        }
        return NOT_NULL;
    }
}


Но есть ё нюанс. Среда разработки подсвечивает в строке, в прочем, как и в прошло варианте:

        if (obj1 == null && obj2 == null) {


Вот это выражение:

obj2 == null)


Если на это выражение навести мышью, можно увидеть подсказку
Я не совсем понял, к чему это. Типа выражение никогда не будет истинным это?
 
 
Сообщения:548
hoz:
Типа выражение никогда не будет истинным это?

Нет. Это выражение будет либо истино либо до него дело не дойдет.
Выполнение до строки if (obj1 == null && obj2 == null) дойдет только в случае когда оба объекта null или оба не null.
В первом случае оно истино, а во втором вычисление условия остановится на obj1 == null и до obj2 == null дело не дойдет (краткая форма оператора И).
Так что можно либо оставить if (obj1 == null) либо написать if (obj1 == null & obj2 == null)
 
 
Сообщения:35
izon:
hoz:
Типа выражение никогда не будет истинным это?

Нет. Это выражение будет либо истино либо до него дело не дойдет.
Выполнение до строки if (obj1 == null && obj2 == null) дойдет только в случае когда оба объекта null или оба не null.
В первом случае оно истино, а во втором вычисление условия остановится на obj1 == null и до obj2 == null дело не дойдет (краткая форма оператора И).
Так что можно либо оставить if (obj1 == null) либо написать if (obj1 == null & obj2 == null)

Логично. Вот мне и попалась ситуация, когда разумно применить булевый оператор сравнений &
 
 
Сообщения:75
По поводу компаратора с проверкой на null, в java8 уже есть готовые решения.
Arrays.sort(students, Comparator.nullsFirst( (s1, s2) -> s1.getSurname().compareToIgnoreCase(s2.getSurname()) ));

Если надо, чтобы null были в конце, то вот такой вариант
Arrays.sort(students, Comparator.nullsLast( (s1, s2) -> s1.getSurname().compareToIgnoreCase(s2.getSurname()) ));
 
 
Сообщения:75
Можно ещё вот такой вариант
Arrays.sort(students, Comparator.nullsFirst( Comparator.comparing(Student::getSurname, String::compareToIgnoreCase) ));

Хорошая статья по компараторам в java8: https://www.baeldung.com/java-8-sort-lambda?utm_source=email-newsletter&utm_medium=email&utm_campaign=auto_33_java&tl_inbound=1&tl_target_all=1&tl_period_type=3
 
 
Сообщения:35
axwer:
Можно ещё вот такой вариант
Arrays.sort(students, Comparator.nullsFirst( Comparator.comparing(Student::getSurname, String::compareToIgnoreCase) ));

Хорошая статья по компараторам в java8: https://www.baeldung.com/java-8-sort-lambda?utm_source=email-newsletter&utm_medium=email&utm_campaign=auto_33_java&tl_inbound=1&tl_target_all=1&tl_period_type=3

Если предыдущий вариант понятен, то этот не очень. Какой-то он чересчур функциональный. Такой подход часто в проектах реальных можно встретить? Или всё же стараются понятнее писать?
 
 
Сообщения:75
В проектах, которых я работал, редко
 
 
Сообщения:35
Кстати, последний вариант тоже интересен. Пришлось чутка заморочиться, что бы его понять. Полезно это для понимания.. капануть вглубь
 
Модераторы:frymock
Сейчас эту тему просматривают:Нет