Javaにおいて、自作クラスのインスタンス同士を比較したり、リストや配列内でソートしたりするためには、適切なインターフェースを実装する必要があります。標準のequals()メソッドは等価判定を行いますが、大小関係の評価や順序付けにはComparableまたはComparatorを用います。
1. Comparableインターフェース(自然順序付け)
Comparableを実装することは、そのクラス自身に「自然な順序(デフォルトの並び順)」を持たせることを意味します。このインターフェースを実装したクラスのインスタンスは、Arrays.sort()やCollections.sort()を引数なしで呼び出すだけでソート可能です。
実装すべきcompareTo(T o)メソッドは、自分自身と対象オブジェクトを比較し、負の数・0・正の数のいずれかを返します。
public class Employee implements Comparable<Employee> {
private String name;
private int salary;
public Employee(String name, int salary) {
this.name = name;
this.salary = salary;
}
@Override
public int compareTo(Employee other) {
// 給与で昇順に並べる
return Integer.compare(this.salary, other.salary);
}
}
2. Comparatorインターフェース(外部比較器)
Comparatorは、クラスのソースコードを修正せずに外部からソート順を定義したい場合に利用します。特に、サードパーティ製のライブラリに含まれるクラスや、複数の異なるソート順(名前順、給与順など)を切り替えたい場合に有効です。
import java.util.Comparator;
public class SalaryComparator implements Comparator<Employee> {
@Override
public int compare(Employee e1, Employee e2) {
return Integer.compare(e1.getSalary(), e2.getSalary());
}
}
// 利用例
// Arrays.sort(employees, new SalaryComparator());
3. 両者の比較と使い分け
両者の主な違いを整理すると以下の通りです。
- Comparable (内部比較器): クラス設計時に「そのクラスが本来どう並ぶべきか」を決定する。実装はシンプルだが、ソースコードの変更が必要。
- Comparator (外部比較器): 外部からソートのルールを指定する。既存のクラスを改変せずに、動的に異なるロジックを注入できる。
特にComparatorを使用する場合、汎用的な比較クラスを作成したり、Java 8以降であればラムダ式やComparator.comparingInt()のようなメソッドを使用して、より簡潔に記述することが推奨されます。
// Java 8以降の簡潔な書き方
import java.util.Arrays;
import java.util.Comparator;
Arrays.sort(employees, Comparator.comparingInt(Employee::getSalary));