ZetCode

Java Collections.sort 方法

上次修改时间:2025 年 4 月 20 日

Collections.sort 方法是 Java 的 java.util.Collections 类中的一个实用方法。它提供了对 List 中的元素进行排序的功能。该方法有两种变体:一种根据自然顺序排序,另一种使用 Comparator。

排序是编程中的一项基本操作。Collections.sort 方法为 List 提供了高效的排序算法。它使用一种改进的归并排序算法,提供 n log(n) 的性能。

Collections.sort 概述

Collections.sort 方法将指定的列表按升序排序。元素必须实现 Comparable 接口才能进行自然排序。或者,您可以提供一个 Comparator 用于自定义排序。

排序是稳定的,这意味着相等的元素不会被重新排序。该方法在原地操作,修改原始列表。对于不可变列表,它会抛出 UnsupportedOperationException。

使用 Collections.sort 的基本排序

此示例演示了 Collections.sort 的最简单用法。我们创建一个 String 列表并按自然顺序对它们进行排序。String 实现了 Comparable 接口,因此不需要额外的配置。

BasicSortExample.java
package com.zetcode;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class BasicSortExample {

    public static void main(String[] args) {
        
        List<String> names = Arrays.asList(
            "John", "Adam", "Jane", "Peter", "Mary"
        );
        
        System.out.println("Before sorting: " + names);
        
        Collections.sort(names);
        
        System.out.println("After sorting: " + names);
    }
}

此代码创建一个名称列表并按字母顺序对其进行排序。输出显示了排序前后的列表。由于它使用 String 的自然顺序,因此排序区分大小写。

Collections.sort 方法会修改原始列表。如果您需要保留原始顺序,请在排序之前创建一个副本。

排序自定义对象

要在 Java 中对自定义对象进行排序,您可以实现 Comparable 接口以进行自然排序,或者提供自定义 Comparator 以进行特定排序逻辑。此示例演示了 Person 记录实现 Comparable,以根据 name 字段定义自然顺序。

CustomObjectSort.java
package com.zetcode;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

record Person(String name, int age) implements Comparable<Person> {
    @Override
    public int compareTo(Person other) {
        return this.name.compareTo(other.name);
    }
}

public class CustomObjectSort {

    public static void main(String[] args) {

        List<Person> people = new ArrayList<>();
        people.add(new Person("John", 25));
        people.add(new Person("Adam", 30));
        people.add(new Person("Jane", 22));

        System.out.println("Before sorting: " + people);
        Collections.sort(people);
        System.out.println("After sorting: " + people);
    }
}

Person 记录重写了 compareTo 方法,委托给 StringcompareTo 方法以按字母顺序对名称进行排序。Collections.sort 方法使用此自然顺序按名称升序排列 Person 对象。

输出显示了按名称字母顺序排序的列表,如自然顺序所定义。当对象具有固有的或“默认”排序顺序时,实现 Comparable 接口是一种清晰有效的做法,这使得代码更易于理解和维护。

使用 Comparator 排序

当您无法修改类或需要不同的排序顺序时,请使用 Comparator。此示例演示了如何使用 Comparator 按年龄对 Person 进行排序。

ComparatorSort.java
package com.zetcode;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

record Person(String name, int age) {}

public class ComparatorSort {

    public static void main(String[] args) {

        List<Person> people = new ArrayList<>();
        people.add(new Person("John", 25));
        people.add(new Person("Adam", 30));
        people.add(new Person("Jane", 22));

        System.out.println("Original order: " + people);

        // Sort by age using Comparator
        Collections.sort(people, Comparator.comparingInt(Person::age));

        System.out.println("Sorted by age: " + people);
    }
}

此示例使用一个比较器按年龄排序,使用方法引用 Comparator.comparingInt(Person::age) 创建。与匿名实现不同,这种方法利用了现代 Java 函数式编程,以实现简洁易读的代码。通过直接引用 age 字段,比较被简化,并避免了手动实现 compare 方法。

输出显示了按年龄升序排序的列表。这演示了比较器的灵活性,比较器特别适用于自定义排序逻辑,包括处理多个标准或动态排序。

用于排序的 Lambda 表达式

Lambda 表达式简化了 Comparator 的创建。此示例演示了如何将 lambda 与 Collections.sort 一起使用以实现简洁的代码。

LambdaSort.java
package com.zetcode;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

record Person(String name, int age) {}

public class LambdaSort {

    public static void main(String[] args) {

        List<Person> people = new ArrayList<>();
        people.add(new Person("John", 25));
        people.add(new Person("Adam", 30));
        people.add(new Person("Jane", 22));

        System.out.println("Original order: " + people);

        // Sort by name using lambda
        Collections.sort(people, Comparator.comparing(Person::name));
        System.out.println("Sorted by name: " + people);

        // Sort by age using lambda
        Collections.sort(people, Comparator.comparingInt(Person::age));
        System.out.println("Sorted by age: " + people);
    }
}

Lambda 表达式使 Comparator 代码更加简洁。第一个排序使用 lambda 比较名称。第二个排序比较年龄,每行代码只需要一行。

输出演示了两种排序顺序。当您需要在应用程序的不同部分中使用多个排序标准时,lambda 表达式特别有用。

反向排序

Collections.sort 可以使用 Comparator.reverseOrderCollections.reverseOrder 按相反的顺序排序。此示例演示了这两种方法。

ReverseSort.java
package com.zetcode;

import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class ReverseSort {

    public static void main(String[] args) {

        List<String> names = Arrays.asList(
                "John", "Adam", "Jane", "Peter", "Mary"
        );

        System.out.println("Original order: " + names);

        // Natural order sort
        Collections.sort(names);
        System.out.println("Natural order: " + names);

        // Reverse order using reverseOrder()
        Collections.sort(names, Collections.reverseOrder());
        System.out.println("Reverse order: " + names);

        // Alternative reverse sort
        names.sort(Comparator.reverseOrder());
        System.out.println("Alternative reverse: " + names);
    }
}

此示例首先按自然顺序对名称进行排序,然后反转顺序。Collections.reverseOrder 返回一个 Comparator,它会反转自然顺序。另一种方法是直接使用 List 的 sort 方法。

输出显示了每个排序步骤。反向排序对于以降序显示数据(例如首先显示最高分数)很有用。

使用多个条件的排序

对于具有多个字段的复杂排序,请使用 Comparator 链。此示例使用 thenComparing 按名称然后按年龄对 Person 进行排序。

MultiCriteriaSort.java
package com.zetcode;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

record Person(String name, int age) {
}

public class MultiCriteriaSort {

    public static void main(String[] args) {

        List<Person> people = new ArrayList<>();
        people.add(new Person("John", 25));
        people.add(new Person("Adam", 30));
        people.add(new Person("Jane", 22));
        people.add(new Person("Adam", 25));

        System.out.println("Original order: " + people);

        // Sort by name then age
        Collections.sort(people, Comparator
                .comparing(Person::name)
                .thenComparingInt(Person::age)
        );

        System.out.println("Sorted by name then age: " + people);
    }
}

此示例使用 Java 8 的 Comparator.comparing 和 thenComparing 方法。首先,它按名称排序,然后按年龄对具有相同名称的人进行排序。方法引用使代码更具可读性。

输出显示了主要按名称排序,其次按年龄排序的列表。当处理复杂的排序要求时,此技术至关重要。

不区分大小写的排序

对于不区分大小写的字符串排序,请使用 String.CASE_INSENSITIVE_ORDER 或自定义 Comparator。此示例演示了这两种方法。

CaseInsensitiveSort.java
package com.zetcode;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class CaseInsensitiveSort {

    public static void main(String[] args) {
        
        List<String> words = Arrays.asList(
            "apple", "Orange", "banana", "PEAR", "Grape"
        );
        
        System.out.println("Original order: " + words);
        
        // Case-sensitive sort (natural order)
        Collections.sort(words);
        System.out.println("Case-sensitive sort: " + words);
        
        // Case-insensitive sort using String.CASE_INSENSITIVE_ORDER
        Collections.sort(words, String.CASE_INSENSITIVE_ORDER);
        System.out.println("Case-insensitive sort: " + words);
        
        // Alternative using lambda
        Collections.sort(words, String::compareToIgnoreCase);
        System.out.println("Lambda case-insensitive: " + words);
    }
}

该示例首先显示区分大小写的排序,其中大写字母排在小写字母之前。然后它演示了使用 String 的内置 Comparator 和带有 compareToIgnoreCase 的 lambda 的不区分大小写的排序。

输出清楚地显示了区分大小写和不区分大小写的排序之间的区别。不区分大小写的排序通常是用户在应用程序中期望的。

来源

Java Collections.sort 文档

在本文中,我们深入探讨了 Java 的 Collections.sort 方法。我们涵盖了基本排序、自定义对象、Comparators、lambdas、反向排序、多条件排序和大小写敏感性。掌握这些技术对于有效的 Java 开发至关重要。

作者

我的名字是 Jan Bodnar,我是一位经验丰富的程序员,在这一领域拥有多年经验。我从 2007 年开始撰写编程文章,此后撰写了 1,400 多篇文章和 8 本电子书。凭借超过 8 年的教学经验,我致力于分享我的知识并帮助他人掌握编程概念。

列出所有Java教程