如何驯服混乱:在Java中按任意字段对ArrayList对象排序
\n\n想象一下:您正在编写一个图书目录应用程序。您有一个Book类,包含title、author、price和year字段。您将几十本书放入ArrayList中。然后用户要求:“先显示最新的!”,一分钟后又说:“不,按价格排序!”
如果您曾经遇到过这样的问题,您就会知道——简单地调用Collections.sort(list)是行不通的。Java无法读懂您的想法。您需要告诉它:具体按哪个字段排序。这正是Stack Overflow上关于自定义对象排序最热门的问题。
在本文中,我们将介绍按对象属性对ArrayList进行排序的所有方法:从经典的Comparable到优雅的Lambda表达式和Stream API。开始吧!
准备工作:将要排序的类
\n\n为了举例,我们创建一个简单的Person类:
public class Person {\n private String name;\n private int age;\n private double salary;\n\n public Person(String name, int age, double salary) {\n this.name = name;\n this.age = age;\n this.salary = salary;\n }\n\n // Getter方法(为简洁起见省略Setter)\n public String getName() { return name; }\n public int getAge() { return age; }\n public double getSalary() { return salary; }\n\n @Override\n public String toString() {\n return name + " (" + age + "岁, $" + salary + ")";\n }\n}\n\n\n然后填充我们的列表:
\n\nArrayList<Person> people = new ArrayList<>();\npeople.add(new Person("安娜", 28, 55000));\npeople.add(new Person("鲍里斯", 35, 72000));\npeople.add(new Person("维克多", 22, 48000));\npeople.add(new Person("加林娜", 30, 62000));\n\n\n现在一切准备就绪,可以开始实验了。如何按年龄排序这个列表?按姓名?按工资?Java至少有三种方法。我们从最基础的开始。
\n\n方法1:Comparable — 将排序逻辑直接嵌入类中
\n\nComparable接口是对象的“自然顺序”。如果您希望您的对象始终按一个字段排序(例如按年龄),请实现此接口。
修改我们的Person类:
public class Person implements Comparable<Person> {\n // ... 字段、构造方法、Getter方法 ...\n\n @Override\n public int compareTo(Person other) {\n return Integer.compare(this.age, other.age);\n }\n}\n\n\n现在排序只需一行代码:
\n\nCollections.sort(people);\nSystem.out.println(people);\n// 输出:[维克多 (22岁, $48000), 安娜 (28岁, $55000), 加林娜 (30岁, $62000), 鲍里斯 (35岁, $72000)]\n\n\n优点:简单,无需考虑外部比较器。
\n缺点:您在类中“硬编码”了仅一种排序方式。如果明天需要按姓名排序,就必须修改类。
顺便说一下,要实现反向排序(从大到小),可以使用Collections.reverseOrder():
Collections.sort(people, Collections.reverseOrder());\n\n\n方法2:Comparator — 无需修改类的灵活性
\n\n当需要在程序的不同位置以不同方式排序时,Comparator就派上用场了。它是一个单独的类或匿名类,包含比较逻辑。
匿名类——老派方法
\n\nCollections.sort(people, new Comparator<Person>() {\n @Override\n public int compare(Person p1, Person p2) {\n return p1.getName().compareTo(p2.getName());\n }\n});\n\n\n虽然可行,但看起来冗长。在