Java 集合排序
在Java编程中,排序是一项非常常见的操作。当你处理集合(如List、Set等)时,经常需要对元素进行排序以便更好地展示或处理数据。Java提供了多种强大而灵活的方式来对集合进行排序,本文将详细介绍这些排序方法。
排序基础
在Java中,对集合进行排序主要有两种方式:
- 使用
Comparable
接口(自然排序) - 使用
Comparator
接口(比较器排序)
这两种方式分别适用于不同的场景,我们将逐一详细讲解。
Collections工具类
Java提供了Collections
工具类,其中包含了多个用于排序的静态方法。最常用的是Collections.sort()
方法。
基本使用
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class BasicSortExample {
public static void main(String[] args) {
List<String> fruits = new ArrayList<>();
fruits.add("Banana");
fruits.add("Apple");
fruits.add("Pear");
fruits.add("Orange");
System.out.println("排序前:" + fruits);
// 使用Collections.sort()方法排序
Collections.sort(fruits);
System.out.println("排序后:" + fruits);
}
}
输出:
排序前:[Banana, Apple, Pear, Orange]
排序后:[Apple, Banana, Orange, Pear]
Collections.sort()
方法默认按照字母顺序(字典顺序)对字符串进行排序。对于数字,则按照数值大小排序。
Comparable接口
如果你想让自定义类的对象可以被自然排序,你需要实现Comparable
接口。这个接口只有一个方法:compareTo()
。
public interface Comparable<T> {
public int compareTo(T o);
}
compareTo()
方法返回一个整数:
- 如果当前对象小于比较对象,返回负数
- 如果当前对象等于比较对象,返回0
- 如果当前对象大于比较对象,返回正数
示例:学生按成绩排序
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
class Student implements Comparable<Student> {
private String name;
private int score;
public Student(String name, int score) {
this.name = name;
this.score = score;
}
@Override
public int compareTo(Student other) {
// 按分数从高到低排序
return other.score - this.score;
}
@Override
public String toString() {
return name + ":" + score;
}
}
public class ComparableExample {
public static void main(String[] args) {
List<Student> students = new ArrayList<>();
students.add(new Student("张三", 85));
students.add(new Student("李四", 92));
students.add(new Student("王五", 78));
students.add(new Student("赵六", 88));
System.out.println("排序前:" + students);
Collections.sort(students);
System.out.println("排序后:" + students);
}
}
输出:
排序前:[张三:85, 李四:92, 王五:78, 赵六:88]
排序后:[李四:92, 赵六:88, 张三:85, 王五:78]
实现Comparable
接口是让类具备"自然排序"能力的方式,适合在类设计时就确定排序规则的情况。
Comparator接口
有时候,我们需要对某个类的对象进行不同方式的排序,而不仅仅是一种自然排序。或者,我们需要排序的类是第三方提供的,无法修改其源码来实现Comparable
接口。这时,我们可以使用Comparator
接口。
public interface Comparator<T> {
int compare(T o1, T o2);
}
compare()
方法接收两个参数,并返回一个整数:
- 如果o1小于o2,返回负数
- 如果o1等于o2,返回0
- 如果o1大于o2,返回正数
示例:按不同属性排序
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
@Override
public String toString() {
return name + "(" + age + ")";
}
}
public class ComparatorExample {
public static void main(String[] args) {
List<Person> people = new ArrayList<>();
people.add(new Person("张三", 25));
people.add(new Person("李四", 22));
people.add(new Person("王五", 28));
people.add(new Person("赵六", 22));
System.out.println("原始列表:" + people);
// 按年龄升序排序
Collections.sort(people, new Comparator<Person>() {
@Override
public int compare(Person p1, Person p2) {
return p1.getAge() - p2.getAge();
}
});
System.out.println("按年龄升序:" + people);
// 按姓名字母顺序排序
Collections.sort(people, new Comparator<Person>() {
@Override
public int compare(Person p1, Person p2) {
return p1.getName().compareTo(p2.getName());
}
});
System.out.println("按姓名字母顺序:" + people);
}
}
输出:
原始列表:[张三(25), 李四(22), 王五(28), 赵六(22)]
按年龄升序:[李四(22), 赵六(22), 张三(25), 王五(28)]
按姓名字母顺序:[李四(22), 王五(28), 张三(25), 赵六(22)]
使用Lambda表达式简化
Java 8引入的Lambda表达式可以让Comparator
的创建更加简洁:
// 按年龄升序
Collections.sort(people, (p1, p2) -> p1.getAge() - p2.getAge());
// 按姓名字母顺序
Collections.sort(people, (p1, p2) -> p1.getName().compareTo(p2.getName()));
Arrays.sort() 方法
对于数组,我们可以使用Arrays.sort()
方法进行排序:
import java.util.Arrays;
public class ArraySortExample {
public static void main(String[] args) {
// 排序整数数组
int[] numbers = {5, 2, 9, 1, 5, 6};
System.out.println("排序前:" + Arrays.toString(numbers));
Arrays.sort(numbers);
System.out.println("排序后:" + Arrays.toString(numbers));
// 排序字符串数组
String[] names = {"Tom", "Jerry", "Mickey", "Donald"};
System.out.println("排序前:" + Arrays.toString(names));
Arrays.sort(names);
System.out.println("排序后:" + Arrays.toString(names));
}
}
输出:
排序前:[5, 2, 9, 1, 5, 6]
排序后:[1, 2, 5, 5, 6, 9]
排序前:[Tom, Jerry, Mickey, Donald]
排序后:[Donald, Jerry, Mickey, Tom]
List接口的sort方法
Java 8引入了List
接口的sort
方法,可以直接对列表进行排序,无需使用Collections.sort()
:
import java.util.ArrayList;
import java.util.List;
public class ListSortExample {
public static void main(String[] args) {
List<Integer> numbers = new ArrayList<>();
numbers.add(5);
numbers.add(2);
numbers.add(9);
numbers.add(1);
System.out.println("排序前:" + numbers);
numbers.sort((a, b) -> a - b); // 升序
System.out.println("升序排序后:" + numbers);
numbers.sort((a, b) -> b - a); // 降序
System.out.println("降序排序后:" + numbers);
}
}
输出:
排序前:[5, 2, 9, 1]
升序排序后:[1, 2, 5, 9]
降序排序后:[9, 5, 2, 1]
复杂排序示例
在实际应用中,我们经常需要处理更复杂的排序情况,比如多条件排序。
多条件排序示例
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
class Employee {
private String name;
private String department;
private int salary;
public Employee(String name, String department, int salary) {
this.name = name;
this.department = department;
this.salary = salary;
}
public String getName() { return name; }
public String getDepartment() { return department; }
public int getSalary() { return salary; }
@Override
public String toString() {
return name + " (" + department + ", " + salary + ")";
}
}
public class ComplexSortExample {
public static void main(String[] args) {
List<Employee> employees = new ArrayList<>();
employees.add(new Employee("张三", "技术部", 8000));
employees.add(new Employee("李四", "市场部", 9000));
employees.add(new Employee("王五", "技术部", 8000));
employees.add(new Employee("赵六", "人事部", 7000));
employees.add(new Employee("钱七", "市场部", 7000));
System.out.println("原始数据:");
employees.forEach(System.out::println);
// 首先按部门排序,然后按薪资降序排序,最后按姓名字母排序
Collections.sort(employees, Comparator
.comparing(Employee::getDepartment)
.thenComparing(Employee::getSalary, Comparator.reverseOrder())
.thenComparing(Employee::getName));
System.out.println("\n排序后:");
employees.forEach(System.out::println);
}
}
输出:
原始数据:
张三 (技术部, 8000)
李四 (市场部, 9000)
王五 (技术部, 8000)
赵六 (人事部, 7000)
钱七 (市场部, 7000)
排序后:
赵六 (人事部, 7000)
李四 (市场部, 9000)
钱七 (市场部, 7000)
张三 (技术部, 8000)
王五 (技术部, 8000)
在上面的例子中,我们使用了Java 8引入的Comparator
接口的默认方法:comparing()
、thenComparing()
和reverseOrder()
。这些方法使多条件排序变得更加简洁。
实际应用案例
电商网站商品排序
想象你正在开发一个电商网站,用户可以按照不同的条件对商品进行排序:
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
class Product {
private String name;
private double price;
private double rating;
private int sales;
public Product(String name, double price, double rating, int sales) {
this.name = name;
this.price = price;
this.rating = rating;
this.sales = sales;
}
// Getters
public String getName() { return name; }
public double getPrice() { return price; }
public double getRating() { return rating; }
public int getSales() { return sales; }
@Override
public String toString() {
return name + " (价格: " + price + ", 评分: " + rating + ", 销量: " + sales + ")";
}
}
public class ECommerceExample {
public static void main(String[] args) {
List<Product> products = new ArrayList<>();
products.add(new Product("笔记本电脑", 5999.0, 4.8, 1200));
products.add(new Product("智能手机", 2999.0, 4.6, 3000));
products.add(new Product("蓝牙耳机", 299.0, 4.9, 5000));
products.add(new Product("平板电脑", 3999.0, 4.7, 800));
products.add(new Product("智能手表", 1299.0, 4.5, 1500));
System.out.println("所有商品:");
products.forEach(System.out::println);
// 按价格从低到高排序
System.out.println("\n按价格从低到高:");
products.sort(Comparator.comparing(Product::getPrice));
products.forEach(System.out::println);
// 按评分从高到低排序
System.out.println("\n按评分从高到低:");
products.sort(Comparator.comparing(Product::getRating).reversed());
products.forEach(System.out::println);
// 按销量从高到低排序
System.out.println("\n按销量从高到低:");
products.sort(Comparator.comparing(Product::getSales).reversed());
products.forEach(System.out::println);
// 综合排序:先按评分降序,评分相同时按销量降序
System.out.println("\n综合排序(评分优先,销量次之):");
products.sort(
Comparator.comparing(Product::getRating).reversed()
.thenComparing(Comparator.comparing(Product::getSales).reversed())
);
products.forEach(System.out::println);
}
}
这个例子展示了电商网站中常见的排序功能,比如按价格、按评分、按销量排序,以及综合排序。
总结
在本文中,我们详细介绍了Java集合排序的多种方法:
- Collections.sort()方法:用于对List集合进行排序
- Comparable接口:实现该接口可以让类具有"自然排序"能力
- Comparator接口:提供更灵活的排序方式,适用于多种排序需求
- Arrays.sort()方法:用于对数组进行排序
- List.sort()方法:Java 8引入的直接对List进行排序的方法
- 多条件排序:使用Comparator接口的默认方法实现复杂的多条件排序
掌握这些排序方法,可以帮助你更高效地处理和展示数据,满足各种业务需求。
练习
为了巩固所学知识,尝试完成以下练习:
- 创建一个
Book
类,包含书名、作者、出版日期和价格。实现Comparable
接口,使Book
对象可以按价格自然排序。 - 使用
Comparator
接口,对Book
对象分别按书名、作者和出版日期排序。 - 实现一个
Student
类,包含姓名、多门课程的成绩。创建一个方法,根据总分或平均分对学生进行排序。 - 设计一个文件系统,可以按文件名、大小、修改日期等多种方式对文件进行排序。
扩展阅读
通过系统学习和实践Java集合排序,你将能够更有效地组织和处理数据,提高应用程序的用户体验和性能。