首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java Comparable 與 Comparator 深度比較:內部排序 vs 外部策略

     編輯:Java 相關知識

核心差異一覽

維度Comparable (內部比較器)Comparator (外部比較器)
套件java.langjava.util
方法int compareTo(T o)int compare(T o1, T o2)
實作位置**類別自身**實作介面**獨立類別**實作介面
排序邏輯**自然順序** (唯一、固定)**定製順序** (可多種、可變)
適用場景類別有明確預設排序 (如 ID、姓名)需多種排序、無法修改類別、第三方類別
TreeSet/TreeMap Key直接支援建構時傳入 new TreeSet<>(comparator)
Collections.sort()sort(list) 自動用 compareTosort(list, comparator) 顯式指定

Comparable 實作範例

public class Person implements Comparable<Person> {
    private String name;
    private int age;

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

    // 自然順序:按姓名字典序
    @Override
    public int compareTo(Person other) {
        return this.name.compareTo(other.name); // 委託給 String 的比較
    }

    // Getter、toString 省略...
}

Comparator 實作範例

// 年齡升序
public class AgeAscComparator implements Comparator<Person> {
    @Override
    public int compare(Person p1, Person p2) {
        return Integer.compare(p1.getAge(), p2.getAge()); // 避免溢位
    }
}

// 年齡降序
public class AgeDescComparator implements Comparator<Person> {
    @Override
    public int compare(Person p1, Person p2) {
        return Integer.compare(p2.getAge(), p1.getAge());
    }
}

// 多欄位複合排序:先按年齡升序,年齡相同再按姓名降序
public class CompositeComparator implements Comparator<Person> {
    @Override
    public int compare(Person p1, Person p2) {
        int ageCmp = Integer.compare(p1.getAge(), p2.getAge());
        if (ageCmp != 0) return ageCmp;
        return p2.getName().compareTo(p1.getName()); // 姓名降序
    }
}

實戰測試

public class SortDemo {
    public static void main(String[] args) {
        List<Person> list = Arrays.asList(
            new Person("ccc", 20),
            new Person("AAA", 30),
            new Person("bbb", 10),
            new Person("ddd", 40)
        );

        System.out.println("原始: " + list);
        
        // 1. 自然順序 (Comparable)
        Collections.sort(list);
        System.out.println("姓名排序: " + list); 
        // [AAA-30, bbb-10, ccc-20, ddd-40]

        // 2. 外部比較器:年齡升序
        Collections.sort(list, new AgeAscComparator());
        System.out.println("年齡升序: " + list);
        // [bbb-10, ccc-20, AAA-30, ddd-40]

        // 3. 外部比較器:年齡降序
        Collections.sort(list, new AgeDescComparator());
        System.out.println("年齡降序: " + list);
        // [ddd-40, AAA-30, ccc-20, bbb-10]

        // 4. Java 8+ Lambda 簡寫
        list.sort(Comparator.comparingInt(Person::getAge)); // 升序
        list.sort(Comparator.comparingInt(Person::getAge).reversed()); // 降序
        list.sort(Comparator.comparing(Person::getName, String.CASE_INSENSITIVE_ORDER)); // 忽略大小寫
        
        // 5. 複合排序
        list.sort(Comparator
            .comparingInt(Person::getAge)
            .thenComparing(Person::getName, Comparator.reverseOrder()));
    }
}

equals() 與 compareTo() 一致性契約

強烈建議:compareTo() 返回 0 應該意味著 equals() 返回 true。

// 正確:比較邏輯與 equals 一致
@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (!(o instanceof Person)) return false;
    Person p = (Person) o;
    return age == p.age && Objects.equals(name, p.name);
}

@Override
public int hashCode() {
    return Objects.hash(name, age);
}

違反此契約會導致 TreeSet、TreeMap 行為異常 (如無法移除元素、重複鍵)。

進階:Comparator 靜態工廠方法 (Java 8+)

Comparator<Person> cmp = Comparator
    .comparing(Person::getName)                    // 主鍵:姓名
    .thenComparingInt(Person::getAge)              // 次鍵:年齡升序
    .thenComparing(Person::getId, Comparator.nullsLast(Comparator.naturalOrder())); // 第三鍵:ID,null 最後

// 反轉
cmp.reversed();

// null 安全
Comparator.nullsFirst(Comparator.naturalOrder());
Comparator.nullsLast(Comparator.reverseOrder());

總結

  • Comparable = 「我**天生**怎麼排」 (自然順序,唯一)
  • Comparator = 「我**想**怎麼排」 (策略模式,多樣、可換)
  • **首選 Comparable** 定義領域模型的自然順序
  • **靈活運用 Comparator** (尤其是 Lambda/Method Reference) 處理 UI 排序、報表排序、多維度排序
  • **保持 equals 與 compareTo 一致**
  • Java 8+ Comparator.comparing... 鏈式 API 讓複合排序極其優雅
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved