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
method.
当你传递函数时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]
- does,
since 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])
.
Using Comparator.comparing()
更安全,因为它比较两个点的平方和而不计算它们的差。它用Double
's compareTo()
相反(假设你的点的坐标是Double
or double
).
换句话说,第一个替代方案使用Function
只需要一点,因为这个函数告诉Comprator.comparing
如何变换这 2 个点中的每一个。
另一方面,第二种选择接受 2 点(这是Comparator.compare()
方法)并确定这两个点的相对顺序。