跳到主要内容

Java 集合排序

在Java编程中,排序是一项非常常见的操作。当你处理集合(如List、Set等)时,经常需要对元素进行排序以便更好地展示或处理数据。Java提供了多种强大而灵活的方式来对集合进行排序,本文将详细介绍这些排序方法。

排序基础

在Java中,对集合进行排序主要有两种方式:

  1. 使用Comparable接口(自然排序)
  2. 使用Comparator接口(比较器排序)

这两种方式分别适用于不同的场景,我们将逐一详细讲解。

Collections工具类

Java提供了Collections工具类,其中包含了多个用于排序的静态方法。最常用的是Collections.sort()方法。

基本使用

java
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()

java
public interface Comparable<T> {
public int compareTo(T o);
}

compareTo()方法返回一个整数:

  • 如果当前对象小于比较对象,返回负数
  • 如果当前对象等于比较对象,返回0
  • 如果当前对象大于比较对象,返回正数

示例:学生按成绩排序

java
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接口。

java
public interface Comparator<T> {
int compare(T o1, T o2);
}

compare()方法接收两个参数,并返回一个整数:

  • 如果o1小于o2,返回负数
  • 如果o1等于o2,返回0
  • 如果o1大于o2,返回正数

示例:按不同属性排序

java
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的创建更加简洁:

java
// 按年龄升序
Collections.sort(people, (p1, p2) -> p1.getAge() - p2.getAge());

// 按姓名字母顺序
Collections.sort(people, (p1, p2) -> p1.getName().compareTo(p2.getName()));

Arrays.sort() 方法

对于数组,我们可以使用Arrays.sort()方法进行排序:

java
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()

java
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]

复杂排序示例

在实际应用中,我们经常需要处理更复杂的排序情况,比如多条件排序。

多条件排序示例

java
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()。这些方法使多条件排序变得更加简洁。

实际应用案例

电商网站商品排序

想象你正在开发一个电商网站,用户可以按照不同的条件对商品进行排序:

java
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集合排序的多种方法:

  1. Collections.sort()方法:用于对List集合进行排序
  2. Comparable接口:实现该接口可以让类具有"自然排序"能力
  3. Comparator接口:提供更灵活的排序方式,适用于多种排序需求
  4. Arrays.sort()方法:用于对数组进行排序
  5. List.sort()方法:Java 8引入的直接对List进行排序的方法
  6. 多条件排序:使用Comparator接口的默认方法实现复杂的多条件排序

掌握这些排序方法,可以帮助你更高效地处理和展示数据,满足各种业务需求。

练习

为了巩固所学知识,尝试完成以下练习:

  1. 创建一个Book类,包含书名、作者、出版日期和价格。实现Comparable接口,使Book对象可以按价格自然排序。
  2. 使用Comparator接口,对Book对象分别按书名、作者和出版日期排序。
  3. 实现一个Student类,包含姓名、多门课程的成绩。创建一个方法,根据总分或平均分对学生进行排序。
  4. 设计一个文件系统,可以按文件名、大小、修改日期等多种方式对文件进行排序。

扩展阅读

通过系统学习和实践Java集合排序,你将能够更有效地组织和处理数据,提高应用程序的用户体验和性能。