使用比较器了解 Java 的 List.sort()



我找到了以下代码,它按Person的年龄降序对personList数组进行排序。

personList.sort((Person p1, Person p2) -> p2.getAge() - p1.getAge());

但是,我很难理解它是如何工作的。似乎sort()函数减去p1p2的年龄,但我不明白这如何允许函数返回排序后的数组。

sort()如何迭代数组并将比较器用于该数组中的每个对象?

这只是Java中比较器的一个(也许)过于聪明的实现。

Comparator接口表示,如果p1应该在p2之前,compare(p1, p2)应该返回一个负数,如果它们应该被视为相同,则返回一个负数,如果p1应该在p2之后返回一个正数。

减法恰好可以做到这一点! 如果p1.getAge()小于p2.getAge(),那么p2.getAge() - p1.getAge()是一个正数,所以p1会追p2——这只是"年龄降序"的另一种说法。

然而,以这种特殊方式编写代码在几个层面上并不是一个好主意——最值得注意的是,减法虽然是一个可爱的技巧,但并不适用于所有整数。 (从技术上讲,你对年龄很好,这永远是非负面的,但你不应该知道这一点。 此外,对于代码的读者来说,找出正确的顺序需要几秒钟 - 即使是一个知道这一切的人。 (对你来说,它需要一个StackOverflow问题。

更好的版本是

import static java.util.Comparator.*;
personList.sort(comparingInt(Person::getAge).reversed());

没有减去任何东西。List#sort的Javadoc很清楚;你基本上是将两个元素比较在一起,以确定它们应该处于什么等级。 这是由Comparator本身指定的,因为您有一些小于零、零或大于零的数值来确定顺序。

在您的情况下,如果 p1 的年龄是 30,p2的年龄是 20,那么您将按降序将 p1 排在 p2 之前进行排序。

它是如何做到的机制是...内部? 取决于有人想要为此实现的排序类型,我认为它可能会根据集合的大小而变化,因为不同的排序在不同情况下效果更好(例如,没有人关心大小为 2 的列表上的气泡排序,但如果你有一个足够大的列表,你会使用 TimSort 进入异国情调)。

比较器的工作原理如下。

如果a < b,则返回compare(a,b)负值,如果a > b则返回正值,如果返回a == b则返回0。 因此,通过减去年龄,您可以获得-,+ and 0效果。 在您的情况下,您以相反的顺序对它们进行排序,因为第一个参数是从第二个参数中减去的。

但是,这是一种非常糟糕的方法,可能会导致某些数字集出现问题。 这是降序排序的更好方法。

Comparator<Integer> comp = (a,b)-> a < b ? 1 : a > b ? -1 : 0;

上面使用了三元运算符,它表示对于(a op b) ? r : s,如果a op b为真,则返回r否则返回s其中r and s可能是常量或表达式。

在某些情况下,您可以使用比较器界面 javadoc 中的预定义比较器。 在您的情况下,这将是reversed()比较器,它反转自然顺序(整数升序)比较。

最新更新