0Pricing
Java Academy · 课时

Comparator 与 Lambda 排序

使用 Lambda 表达式和 Comparator.comparing 工厂方法创建 Comparator 实例

Comparator 与 Lambda 排序 是 CoddyKit 上的免费 Java Academy 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Java Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Java Academy 课程共包含 4 节课。

Comparator 与 Lambda 排序

Comparator<T> 为对象定义外部排序顺序。与可比较接口不同,您可以根据需要创建任意数量的 Comparator,而无需修改类。

创建 Comparator

使用 Lambda 表达式或方法引用创建 Comparator,并将其传递给排序方法。

import java.util.*;

record Product(String name, double price, int stock) {}

List<Product> products = new ArrayList<>(List.of(
    new Product("Mouse",    29.99, 50),
    new Product("Laptop",  999.00, 5),
    new Product("USB Hub",  24.99, 100)
));

// Lambda comparator
products.sort((a, b) -> Double.compare(a.price(), b.price()));
System.out.println(products);
// [USB Hub, Mouse, Laptop] (by price ascending)

Comparator.comparing 工厂方法

Comparator.comparing(keyExtractor) 根据键提取函数创建 Comparator,比直接使用 Lambda 表达式更简洁。

import java.util.Comparator;

Comparator<Product> byPrice = Comparator.comparingDouble(Product::price);
Comparator<Product> byName  = Comparator.comparing(Product::name);
Comparator<Product> byStock = Comparator.comparingInt(Product::stock);

products.sort(byPrice);
System.out.println(products); // sorted by price ascending

products.sort(byName);
System.out.println(products); // sorted alphabetically

reversed()

reversed() 会反转任意比较器的顺序。

import java.util.Comparator;

Comparator<Product> mostExpensiveFirst =
    Comparator.comparingDouble(Product::price).reversed();

products.sort(mostExpensiveFirst);
System.out.println(products);
// [Laptop($999.0), Mouse($29.99), USB Hub($24.99)]

naturalOrder 与 reverseOrder

Comparator.naturalOrder() 使用类的可比较接口定义的顺序。reverseOrder() 会将其反转。

List<String> names = new ArrayList<>(List.of("Charlie", "Alice", "Bob"));

names.sort(Comparator.naturalOrder());
System.out.println(names); // [Alice, Bob, Charlie]

names.sort(Comparator.reverseOrder());
System.out.println(names); // [Charlie, Bob, Alice]

// Sort integers descending
List<Integer> nums = new ArrayList<>(List.of(5, 2, 8, 1, 9));
nums.sort(Comparator.reverseOrder());
System.out.println(nums); // [9, 8, 5, 2, 1]

空值安全的比较器

Comparator.nullsFirst() 和 nullsLast() 可以处理空元素而不会产生 NPE。

import java.util.*;

List<String> withNulls = new ArrayList<>(Arrays.asList("Charlie", null, "Alice", null, "Bob"));

withNulls.sort(Comparator.nullsLast(Comparator.naturalOrder()));
System.out.println(withNulls); // [Alice, Bob, Charlie, null, null]

withNulls.sort(Comparator.nullsFirst(Comparator.naturalOrder()));
System.out.println(withNulls); // [null, null, Alice, Bob, Charlie]

使用 Comparator 调用流的 sorted()

将 sorted() 中间流操作与 Comparator 一起使用,即可采用函数式风格进行排序。

import java.util.stream.*;

record Employee(String name, String dept, double salary) {}

List<Employee> employees = List.of(
    new Employee("Alice",   "Engineering", 95000),
    new Employee("Bob",     "Marketing",   72000),
    new Employee("Charlie", "Engineering", 105000)
);

// Sort by salary descending in a stream pipeline
employees.stream()
    .sorted(Comparator.comparingDouble(Employee::salary).reversed())
    .forEach(e -> System.out.println(e.name() + ": $" + e.salary()));
// Charlie: $105000.0 / Alice: $95000.0 / Bob: $72000.0

Comparator:Lambda 表达式与方法引用

当键提取函数是简单的获取器时,方法引用可以让比较器更加简洁。

// Lambda
Comparator<String> c1 = (a, b) -> a.length() - b.length();

// Comparator.comparing with lambda
Comparator<String> c2 = Comparator.comparing(s -> s.length());

// Comparator.comparingInt with method reference (cleanest)
Comparator<String> c3 = Comparator.comparingInt(String::length);

List<String> words = new ArrayList<>(List.of("banana", "fig", "apple", "kiwi"));
words.sort(c3);
System.out.println(words); // [fig, kiwi, apple, banana]

有状态的 Comparator

虽然比较器通常应当是无状态的,但您可以通过构造函数参数注入配置。

class DistanceComparator implements Comparator<String> {
    private final String target;
    DistanceComparator(String target) { this.target = target; }

    @Override
    public int compare(String a, String b) {
        return Integer.compare(distance(a), distance(b));
    }

    private int distance(String s) { return Math.abs(s.length() - target.length()); }
}

List<String> words = new ArrayList<>(List.of("Java", "Go", "Python", "C", "Kotlin"));
words.sort(new DistanceComparator("Java"));
System.out.println(words); // closest length to "Java" first

产品目录的自定义排序

先按是否有货排序,再按价格排序,最后按名称排序产品目录。

import java.util.*;

record Item(String name, double price, boolean inStock) {}

List<Item> catalog = List.of(
    new Item("Laptop",  999.0,  true),
    new Item("Case",     19.99, false),
    new Item("Mouse",    29.99, true),
    new Item("Monitor", 349.0,  true)
);

Comparator<Item> catalogSort =
    Comparator.comparing(Item::inStock).reversed()     // in-stock first
    .thenComparingDouble(Item::price)                  // then cheapest
    .thenComparing(Item::name);                        // then alphabetical

catalog.stream().sorted(catalogSort)
    .forEach(i -> System.out.printf("%s %-15s $%.2f%n",
        i.inStock() ? "[Y]" : "[N]", i.name(), i.price()));

使用 Comparator 调用 Arrays.sort

Arrays.sort(array, comparator) 使用自定义比较器对对象数组进行排序。

String[] words = {"banana", "fig", "apple", "kiwi", "cherry"};

// Sort by length, then alphabetically for same length
Arrays.sort(words,
    Comparator.comparingInt(String::length)
              .thenComparing(Comparator.naturalOrder()));

System.out.println(Arrays.toString(words));
// [fig, kiwi, apple, banana, cherry]

快速检查

Comparator.comparingDouble(Product::price).reversed() 会产生什么结果?

回顾:Comparator 与 Lambda 排序

要点:

  • Comparator<T> 定义外部排序顺序,可根据需要使用任意数量的 Comparator
  • Comparator.comparing(keyExtractor) 根据获取器创建比较器
  • reversed() 会反转任意比较器;naturalOrder()/reverseOrder() 适用于实现可比较接口的类型
  • nullsFirst() 和 nullsLast() 可以安全处理空元素
  • 在流处理流水线中使用 sorted(comparator) 进行函数式风格的排序
  • 比较器可以传递给 sort()、Arrays.sort()、TreeSet 和 TreeMap

常见问题解答

「Comparator 与 Lambda 排序」课时是免费的吗?

是的 — 「Comparator 与 Lambda 排序」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Java Academy 课程的其余内容,请升级到 CoddyKit PRO。 Java Academy 课程共包含 4 节课。

「Comparator 与 Lambda 排序」这节课中我会学到什么?

使用 Lambda 表达式和 Comparator.comparing 工厂方法创建 Comparator 实例 你通过在浏览器中直接运行的动手代码来练习 Java Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Java Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Java Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。

「Comparator 与 Lambda 排序」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Java Academy 课中编写并运行代码吗?

能。每节 Java Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. Comparable 接口
  2. Comparator 与 Lambda 排序
  3. 使用 thenComparing 进行多关键字排序
  4. 实际应用中的数组与集合排序
← 返回 Java Academy