Comparator.comparing
реализован следующим образом:
public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
Function<? super T, ? extends U> keyExtractor)
{
Objects.requireNonNull(keyExtractor);
return (Comparator<T> & Serializable)
(c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
}
т.е. он использует Function
, который вы передаете ему, чтобы преобразовать каждый из сравниваемых элементов в Comparable
, а затем используетComparable
s compareTo
метод.
Когда вы передаете функцию p -> p[0]*p[0] + p[1]*p[1]
, вы конвертируете каждую точку в ее сумму квадратов.Затем, когда Comparator
необходимо сравнить две точки, он сравнивает сумму квадратов двух точек, что почти эквивалентно вычислению разницы сумм квадратов двух точек (это не совсем эквивалентно, поскольку сравнение двухчисла путем вычисления их разности могут привести к неправильному выводу в случае переполнения чисел).
Это именно то, что делает ваш второй Comparator
- (p1, p2) -> p1[0]*p1[0] + p1[1]*p1[1] - p2[0]*p2[0] - p2[1]*p2[1]
-
с p1[0]*p1[0] + p1[1]*p1[1] - p2[0]*p2[0] - p2[1]*p2[1] ==
(p1[0]*p1[0] + p1[1]*p1[1]) - (p2[0]*p2[0] + p2[1]*p2[1])
.
Использование Comparator.comparing()
более безопасно, поскольку оно сравнивает суммы квадратов двух точек без вычисления их разности.Вместо этого он использует Double
compareTo()
(при условии, что координаты ваших точек равны Double
или double
).
Другими словами, в первой альтернативе используется Function
, для которого требуется всего одинточка, поскольку эта функция сообщает Comprator.comparing
, как преобразовать каждую из 2 точек.
С другой стороны, вторая альтернатива принимает 2 точки (которые являются обязательными аргументами метода Comparator.compare()
) и определяетОтносительный порядок этих 2 баллов.