どちらもオブジェクトの順序付け方法を定義していますが、異なる方法で行います:**Comparableはクラスの自然な順序付けを定義し(クラス自体によって実装),Comparator**は外部の別の順序付けを定義します(別のオブジェクト)。選択は,順序付けが本質的か状況的かによります。
public class Person implements Comparable<Person> {
private String name;
private int age;
@Override
public int compareTo(Person other) { // defines THE natural order
return Integer.compare(this.age, other.age); // by age
}
// return: negative if this < other, 0 if equal, positive if this > other
}
List<Person> people = ...;
Collections.sort(people); // uses compareTo — sorts by age (the natural order)
ComparableはcompareTo()を経由してクラスの内部に存在し,単一のデフォルト順序付けを定義します。Collections.sort,TreeSet,TreeMapなどによって自動的に使用されます。
// define orderings OUTSIDE the class — as many as you need
Comparator<Person> byName = (a, b) -> a.getName().compareTo(b.getName());
Comparator<Person> byAge = Comparator.comparingInt(Person::getAge);
people.sort(byName); // sort by name
people.sort(byAge.reversed()); // by age, descending
Comparatorは別のオブジェクトであり,クラスを変更することなく,同じクラスに対して複数の異なる順序付けを定義できます。
Comparator<Person> comp = Comparator
.comparing(Person::getLastName) // primary: last name
.thenComparing(Person::getFirstName) // tie-break: first name
.thenComparingInt(Person::getAge) // then: age
.reversed(); // reverse the whole thing
people.sort(comp);
ビルダースタイルのcomparing/thenComparingメソッドは,複雑な複数フィールドのソートを簡潔で読みやすくします。
Comparable → the class has ONE obvious natural order (numbers by value, strings
alphabetically, dates chronologically); you own the class
Comparator → you need MULTIPLE orderings, situational/custom ordering, OR you
can't modify the class (e.g. sorting a third-party type differently)
オブジェクトの順序付けは常に必要です — リストのソート,TreeSet/TreeMapの使用,最小値/最大値の検索など。
Comparable対Comparatorの違いを理解することで,正しく選択できます:Comparableはクラスの単一の本質的な順序付けのため(組み込み,デフォルトで使用),Comparatorは複数または外部の順序付けの柔軟性のため(同じデータを異なるフィールドでソートする,または制御していないタイプを順序付ける)。
モダンな流暢なComparator API(comparing/thenComparing/reversed)は多段階ソートを優雅にします。
どちらもマスターすること — そしてそれぞれがいつ適用されるか — はソートされたデータ構造を扱うために不可欠であり,Javaでは頻繁に実践的かつインタビュートピックとなります。