Java - 如何使用 Comparator?

你好,未來的 Java 巫師們!? 今天,我們將踏上一段令人興奮的旅程,探索 Java Comparator 的世界。別擔心如果你是編程新手——我將成為你的友好指導者,我們將一步步學習。在本教程結束時,你將能像專家一樣對象進行排序!

Java - Comparators

What is a Comparator?

在我們深入之前,讓我們想像你正在整理書架。你可能想要按照書名、作者或出版日期來排列你的書。在 Java 中,Comparator 就像你的個人文庫管理員,他知道如何根據你選擇的任何標準來排序你的收藏。

從技術角度來看,Comparator 是 Java 中的一個接口,它允許我們為對象定義自定義排序。當我們想要對沒有自然排序的對象進行排序,或者當我們想要以與其自然排序不同的方式對其進行排序時,這特別有用。

The Comparator Interface

讓我們仔細看看 Comparator 接口:

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

別被這個嚇到!其實它比看起來簡單。<T> 只是在說這個接口可以與任何類型的對象一起工作。compare 方法是發生魔法的地 方——它就像請你的文庫管理員比較兩本書。

How the compare Method Works

compare 方法接受兩個對象並返回一個整數:

  • 如果第一個對象被認為是“小於”第二個對象,它將返回一個負數。
  • 如果它們被認為是“相等”的,它將返回零。
  • 如果第一個對象是“大於”第二個對象,它將返回一個正數。

把它想像成一個天平。如果第一個對象更輕,天平會傾向負數一側。如果它們相等,天平會保持在零的平衡。如果第一個對象更重,天平會傾向正數一側。

Creating Your First Comparator

讓我們創建一個簡單的 Comparator 來根據長度對字符串進行排序。我們將稱之為 StringLengthComparator

import java.util.Comparator;

public class StringLengthComparator implements Comparator<String> {
@Override
public int compare(String s1, String s2) {
return s1.length() - s2.length();
}
}

這裡發生了什麼:

  1. 我們從 java.util 引入 Comparator 接口。
  2. 我們創建一個實現 Comparator<String> 的類,意味著它將比較 String 對象。
  3. 我們覆寫 compare 方法來減去第二個字符串的長度。

Using Your Comparator

現在我們有了 Comparator,讓我們用它吧!我們將創建一個字符串列表並對其進行排序:

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

public class ComparatorExample {
public static void main(String[] args) {
List<String> fruits = new ArrayList<>();
fruits.add("Apple");
fruits.add("Pear");
fruits.add("Banana");
fruits.add("Kiwi");

System.out.println("排序前: " + fruits);

Collections.sort(fruits, new StringLengthComparator());

System.out.println("排序後: " + fruits);
}
}

輸出:

排序前: [Apple, Pear, Banana, Kiwi]
排序後: [Pear, Kiwi, Apple, Banana]

讓我們分解一下:

  1. 我們創建了一個水果名稱的列表。
  2. 我們打印原始列表。
  3. 我們使用 Collections.sort() 和我們的自定義 Comparator 來對列表進行排序。
  4. 我們打印排序後的列表。

注意水果現在是按照它們名稱的長度排序的!

Lambda Expressions: A Shortcut

Java 8 引入了 lambda 表達式,這可以使我們的 Comparator 更為簡潔。以下是用 lambda 表達式進行相同範例的代碼:

Collections.sort(fruits, (s1, s2) -> s1.length() - s2.length());

這個單行代碼與我們的 StringLengthComparator 類做完全相同的事情!就像告訴 Java,“嘿,當你比較兩個字符串時,只需要減去它們的長度。”

Sorting Custom Objects

現在,讓我們升級一個檔次,對自定義對象進行排序。想像我們有一個 Person 類:

public class Person {
private String name;
private int age;

public Person(String name, int age) {
this.name = name;
this.age = age;
}

// Getters and setters...

@Override
public String toString() {
return name + " (" + age + ")";
}
}

我們可以創建一個 Comparator 來根據年齡對 Person 對象進行排序:

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

public class PersonSortExample {
public static void main(String[] args) {
List<Person> people = new ArrayList<>();
people.add(new Person("Alice", 25));
people.add(new Person("Bob", 30));
people.add(new Person("Charlie", 22));

System.out.println("排序前: " + people);

Collections.sort(people, Comparator.comparingInt(Person::getAge));

System.out.println("排序後: " + people);
}
}

輸出:

排序前: [Alice (25), Bob (30), Charlie (22)]
排序後: [Charlie (22), Alice (25), Bob (30)]

在這裡,我們使用 Comparator.comparingInt(),它基於整數值創建一個 Comparator —— 在這個例子中,是年齡。Person::getAge 是一個方法引用,告訴 Java 使用 getAge() 方法來獲取比較的值。

Reversing the Order

如果我們想要以降序排序呢?簡單!只需使用 reversed() 方法:

Collections.sort(people, Comparator.comparingInt(Person::getAge).reversed());

這將將我們的 Person 對象從最老到最年輕排序。

Chaining Comparators

有時,我們可能想要按照多個標準進行排序。例如,讓我們按照年齡對 Person 對象進行排序,如果年齡相同,則按照名稱排序:

Comparator<Person> ageAndNameComparator = Comparator
.comparingInt(Person::getAge)
.thenComparing(Person::getName);

Collections.sort(people, ageAndNameComparator);

這創建了一個 Comparator,它首先按照年齡比较,如果年齡相等,則按照名稱比较。

Conclusion

恭喜你!你剛剛學會了 Java Comparator 的來龍去脈。從排序簡單的字符串到複雜的對象,現在你有了按照任何你選擇的方式組織數據的能力。記住,熟能生巧,所以不要害怕嘗試不同的排序標準和對象。

在你繼續你的 Java 旅程時,你會發現 Comparators 是你編程工具包中無價的工具。它們不僅用於排序列表——它們還在許多 Java 集合和算法中用於維護順序和執行有效的搜索。

繼續編碼,繼續學習,最重要的是,玩得開心!誰知道?也許有一天你會寫出一個革命性的排序算法,改變我們組織數據的方式。在那之前,快樂比較!??‍??‍?

Methods of Comparator Interface

這裡是 Comparator 接口中關鍵方法的表格:

方法 描述
compare(T o1, T o2) 比較其兩個參數的順序。
equals(Object obj) 指示此比较器是否與其他某个对象“相等”。
reversed() 返回一個與此比较器相反順序的比较器。
thenComparing(Comparator<? super T> other) 返回一個與另一比较器一起使用字典順序的比较器。
thenComparingInt(ToIntFunction<? super T> keyExtractor) 返回一個與提取 int 排序键的函数一起使用字典順序的比较器。
thenComparingLong(ToLongFunction<? super T> keyExtractor) 返回一個與提取 long 排序键的函数一起使用字典順序的比较器。
thenComparingDouble(ToDoubleFunction<? super T> keyExtractor) 返回一個與提取 double 排序键的函数一起使用字典順序的比较器。

這些方法提供了强大的工具来创建复杂的排序逻辑,允许您为任何数据类型或排序要求构建 sophisticated comparators。

Credits: Image by storyset