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

Java Comparable vs Comparator 完全指南:自然排序、定製排序、TreeSet/Stream 實戰

     編輯:Java 相關知識

核心區別一句話

  • Comparable:**內部**比較,「我自己怎麼排」,類實現 compareTo(T o),**一種**自然順序。
  • Comparator:**外部**比較,「我幫你排」,獨立類實現 compare(T o1, T o2),**多種**定製順序。

Comparable 自然排序實戰

public class Student implements Comparable {
    private int id;
    private String name;
    private double gpa;

    // getter/setter/構造器省略

    @Override
    public int compareTo(Student other) {
        // 按 id 升序
        return Integer.compare(this.id, other.id);
    }

    @Override public String toString() { return "Student(id=" + id + ", name=" + name + ")"; }
}

// 使用
List list = Arrays.asList(new Student(3,"C"), new Student(1,"A"), new Student(2,"B"));
Collections.sort(list); // 或 list.sort(null)
System.out.println(list); // [Student(id=1...), Student(id=2...), Student(id=3...)]

Comparator 定製排序實戰

1. 匿名內部類 / Lambda(Java 8+ 推薦)

// 按 GPA 降序
list.sort((s1, s2) -> Double.compare(s2.getGpa(), s1.getGpa()));

// 多字段:先 GPA 降序,再 id 升序
list.sort(Comparator
    .comparing(Student::getGpa).reversed()
    .thenComparing(Student::getId));

// 空值安全:null 排最後
list.sort(Comparator.nullsLast(Comparator.comparing(Student::getName)));

2. 獨立 Comparator 類(復用、序列化、Spring Bean 注入)

public class StudentNameComparator implements Comparator, Serializable {
    @Override
    public int compare(Student s1, Student s2) {
        return s1.getName().compareTo(s2.getName());
    }
}

// 使用
list.sort(new StudentNameComparator());

TreeSet / TreeMap 依賴比較器

構造方式比較來源適用場景
new TreeSet()元素必須實現 Comparable單一自然順序、元素類可控
new TreeSet(comparator)外部 Comparator多種順序、元素類不可修改(如第三方類)
// 同一數據,兩種視圖
Set byId = new TreeSet<>(list); // 自然順序
Set byGpa = new TreeSet<>(Comparator.comparing(Student::getGpa).reversed());
byGpa.addAll(list); // 自動按 GPA 降序去重

Stream 排序

List top3 = list.stream()
    .sorted(Comparator.comparing(Student::getGpa).reversed())
    .limit(3)
    .toList();

避坑指南

  1. compareTo 與 equals 不一致:compareTo(e1, e2) == 0 應隱含 e1.equals(e2),否則 TreeSet 會出現「邏輯相等但集合視為不同」的 Bug。
  2. 溢出風險:return this.id - other.id 若 id 差值超過 Integer.MAX_VALUE 會溢出,**必須用 Integer.compare 或 Long.compare**。
  3. 空指針:Comparator 鏈中加入 Comparator.nullsFirst/Last,或確保字段非空。
  4. 序列化:作為 TreeSet 比較器的 Comparator 必須實現 Serializable,否則集合序列化失敗。

總結選型表

場景推薦
實體類有明顯「自然順序」(如 ID、時間戳)實現 Comparable
需要多種排序(按姓名、按成績、按註冊時間)編寫多個 Comparator
第三方類無法修改外部 Comparator
TreeSet/TreeMap 去重並排序構造時傳入 Comparator
Stream/Collections.sort 一次性排序Lambda 內聯 Comparator

掌握 Comparable 定自然序、Comparator 定定製序、Comparator.comparing/thenComparing/nullsFirst 鏈式組合,即可輕鬆駕馭 Java 所有排序場景。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved