Цепочка компараторов в java
чтение Java учебник Oracle по интерфейсам что дает пример Card
(игральные карты) я пытался понять методы по умолчанию, в интерфейсах. Вот ссылке раздел "интеграция методов по умолчанию в существующие интерфейсы". Теперь в последнем разделе они отсортировали карты сначала по рангу, а затем по мастям. Были приведены следующие логики. Предположим, что все интерфейсы, функции или классы, которые используются определено и принимает Comparator
логика 1:
package defaultmethods;
import java.util.*;
import java.util.stream.*;
import java.lang.*;
public class SortByRankThenSuit implements Comparator<Card> {
public int compare(Card firstCard, Card secondCard) {
int compVal =
firstCard.getRank().value() - secondCard.getRank().value();
if (compVal != 0)
return compVal;
else
return firstCard.getSuit().value() - secondCard.getSuit().value();
}
}
логика 2:
myDeck.sort(
Comparator
.comparing(Card::getRank)
.thenComparing(Comparator.comparing(Card::getSuit)));
теперь у меня возникли некоторые проблемы в понимании второй логики. Я читал компаратор интерфейсы и новые статические методы, которые были включены в Java 1.8 . Теперь я понимаю, что-то вроде этого myDeck.sort(Comparator.comparing(Card::getRank))
который сортируется по рангу, но после чтения документация thenComparing
, я не могу понять, как thenComparing
возвращает a Comparator
который достигает вышеуказанной логики 1. Он внутренне строит что-то вроде if-else
строительство, как указано в логике 1 ?
2 ответов
Да, он создает внутренне что-то подобное, только с более промежуточных лямбды. Предполагая, что ваш getRank
и getSuit
методы возвращают некоторые экземпляры сопоставимых классов Rank
и Suit
в вашем случае вы эффективно иметь:
Function<Card, Rank> toRank = Card::getRank;
Comparator<Card> comp1 = (a, b) -> toRank.apply(a).compareTo(toRank.apply(b));
Function<Card, Suit> toSuit = Card::getSuit;
Comparator<Card> comp2 = (a, b) -> toSuit.apply(a).compareTo(toSuit.apply(b));
Comparator<Card> result = (a, b) -> {
int res = comp1.compare(a, b);
return res != 0 ? res : comp2.compare(a, b);
};
поэтому после вставки (которая может быть выполнена JIT-компилятором) у вас может быть что-то вроде этого:
Comparator<Card> result = (a, b) -> {
int res = a.getRank().compareTo(b.getRank());
return res != 0 ? res : a.getSuit().compareTo(b.getSuit());
};
обратите внимание, что вы можете использовать простой вариант:
myDeck.sort(
Comparator
.comparing(Card::getRank)
.thenComparing(Card::getSuit));
это реализация на моей машине (Oracle JDK 8u40)
default Comparator<T> thenComparing(Comparator<? super T> other) {
Objects.requireNonNull(other);
return (Comparator<T> & Serializable) (c1, c2) -> {
int res = compare(c1, c2);
return (res != 0) ? res : other.compare(c1, c2);
};
}
Так что да, это по существу, если else (точнее, троичный оператор).