Компаратор Java 8 с условием if
Я хочу отсортировать список объектов, которые я получаю из базы данных по дате. Проблема в том, что расположение даты (таблица1, таблица2) зависит от ObjectType
, Если это 1, то дата должна быть выбрана из первой таблицы, если это 2, чем из второй. Я начал так:
objectList.stream().sorted((h1,h2)->
if(h1.getObjectType().getId()==1){
h1.getObject().getTable1().getTime()}//here is the problem
);
Но потом я запутался, потому что после if
пункт я не могу просто добавить .compareTo
, Есть ли способ сделать компаратор Java 8, используя лямбда-выражения с if
статья?
2 ответа
Здесь происходит несколько вещей одновременно.
Во-первых, если вы хотите использовать if-else
В операторе внутри лямбды вам нужно использовать выражение лямбда (вид с фигурными скобками) вместо выражения лямбда (в котором фигурные скобки опущены). С заявлением лямбда, вы должны использовать return
явно, тогда как в лямбда-выражении возвращаемое значение неявно является просто результатом вычисления выражения.
У вас есть условная логика для выбора значения для сравнения. Я предполагаю, что эту логику нужно применять независимо к каждому из двух сравниваемых объектов, так что это означает, что для простого способа потребуется дважды выписать логику.
Наконец, вам нужно написать логику для фактического сравнения.
В этом примере я предполагаю, что сортируемые объекты имеют тип Obj
и что значения, по которым они сортируются, имеют тип ObjDate
который я далее предположу, чтобы быть сопоставимыми друг с другом. (То есть, ObjDate implements Comparable<ObjDate>
.) Я также предполагаю, что идентификаторы объектов равны 1 или 2, поэтому я не буду обрабатывать случай, когда значение является чем-то другим.
Вот полностью выписанный компаратор, использующий лямбда-выражение:
objectList.stream().sorted((h1, h2) -> {
ObjDate h1date;
ObjDate h2date;
if (h1.getObjectType().getId() == 1) {
h1date = h1.getObject().getTable1().getTime();
} else {
h1date = h1.getObject().getTable2().getTime();
}
if (h2.getObjectType().getId() == 1) {
h2date = h2.getObject().getTable1().getTime();
} else {
h2date = h2.getObject().getTable2().getTime();
}
return h1date.compareTo(h2date);
});
Тьфу! Писать компараторы - это весело, не правда ли?:-)
По сути, идея состоит в том, чтобы применить логику get-from-table1-or-table2, чтобы извлечь правильное значение для первого объекта, а затем то же самое для второго объекта. Наконец, верните результат их сравнения.
Это будет работать, но здесь есть некоторый очевидный дублированный код. Общий код может упоминаться как средство извлечения ключей, поскольку, учитывая объект для сравнения, он извлекает ключ, который используется в качестве основы для сравнения. Вот метод извлечения ключа, который делает это для одного объекта:
ObjDate getSortingDate(Obj obj) {
if (obj.getObjectType().getId() == 1) {
return obj.getObject().getTable1().getTime();
} else {
return obj.getObject().getTable2().getTime();
}
}
Теперь, когда у нас это есть, мы можем значительно упростить компаратор:
objectList.stream().sorted((h1, h2) -> {
ObjDate h1date = getSortingDate(h1);
ObjDate h2date = getSortingDate(h2);
return h1date.compareTo(h2date);
});
Если мы свернем локальные переменные, мы можем преобразовать это в выражение лямбда:
objectList.stream().sorted(
(h1, h2) -> getSortingDate(h1).compareTo(getSortingDate(h2)));
Наконец, идея извлечения ключа из двух объектов и сравнения их настолько распространена среди компараторов, что есть вспомогательный метод, который делает это за вас: Comparator.comparing(keyExtractor)
, Учитывая два объекта, он запускает механизм извлечения ключей для обоих объектов и сравнивает их. (Точнее, он возвращает функцию, которая делает это.) Мы можем использовать это напрямую, чтобы еще больше упростить вещи:
objectList.stream().sorted(Comparator.comparing(this::getSortingDate));
Поскольку у вас есть более одной строки кода, вам нужен блок в вашем лямбда-выражении. Если у вас есть лямбда-блок, вам нужно что-то вернуть.