Menu
Coddy logo textTech

Comparator インターフェース

CoddyのJavaジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 45/87。

Comparable はクラスの自然な順序を定義しますが、時にはオブジェクトを別の方法でソートする必要がある場合があります。Comparator インターフェースを使用すると、元のクラスを変更せずに、別の比較ロジックを作成できます。

Comparator は、同じ型の2つのオブジェクトを比較する外部オブジェクトです。これは、複数のソートオプションが必要な場合や、クラス自体を修正できない場合に役立ちます:

import java.util.Comparator;

class NameComparator implements Comparator<Person> {
    @Override
    public int compare(Person p1, Person p2) {
        return p1.getName().compareTo(p2.getName());
    }
}

class AgeComparator implements Comparator<Person> {
    @Override
    public int compare(Person p1, Person p2) {
        return p1.getAge() - p2.getAge();
    }
}

その後、コンパレータをソートメソッドに渡すことができます:

List<Person> people = new ArrayList<>();
people.add(new Person("Charlie", 30));
people.add(new Person("Alice", 25));

Collections.sort(people, new NameComparator());  // 名前でソート
Collections.sort(people, new AgeComparator());   // 年齢でソート

Comparatorは関数型インターフェースであるため、ラムダ式を使用して簡潔なコードを書くことができます:

Collections.sort(people, (p1, p2) -> p1.getName().compareTo(p2.getName()));

主な違い:Comparable は比較対象のクラス自体によって実装され、1つの自然な順序を定義します。一方、Comparator は無制限のカスタム順序を定義できる別のクラスです。

challenge icon

チャレンジ

簡単

Comparator インターフェースの強力さを示す従業員ソートシステムを構築しましょう。Employee クラス自体を変更することなく、給与順や名前順など、さまざまな方法で従業員をソートするための複数のコンパレータを作成します。

コードは以下の4つのファイルに分けて構成します:

  • Employee.java: 3つのプライベートフィールド name (String)、department (String)、salary (double) を持つ従業員を表すクラスを作成します。すべてのフィールドを初期化するコンストラクタと、それぞれのゲッターメソッドを含めてください。toString() をオーバーライドして、[name] ([department]) - $[salary] を返すようにします。
  • SalaryComparator.java: 従業員を給与の降順(給与の高い順)でソートするコンパレータを作成します。Comparator<Employee> インターフェースとその compare() メソッドを実装してください。給与値の安全な比較には Double.compare() を使用します。
  • NameComparator.java: 従業員を名前のアルファベット順で昇順(AからZ)にソートする別のコンパレータを作成します。Comparator<Employee> を実装し、比較には String の compareTo() メソッドを使用します。
  • Main.java: 従業員のリストを作成し、作成したコンパレータを使用してソートすることで、すべてをまとめます。3人の従業員の入力を、各行 name,department,salary の形式で受け取ります。

    従業員の ArrayList を作成し、両方のソート方法を実演してください:

    1. まず、SalaryComparator を使用して給与順にソートし、各従業員を出力します。
    2. 空行を1行出力します。
    3. 次に、NameComparator を使用して名前順にソートし、各従業員を出力します。

入力として、従業員データが name,department,salary の形式で含まれる3行を受け取ります。

例えば、入力行は Alice,Engineering,75000.0 のようになります。

コンパレータファイルでは java.util.Comparator を、Main ファイルでは java.util.ArrayListjava.util.Collectionsjava.util.Scanner をインポートすることを忘れないでください。コンパレータを使用することで、外部から複数のソート戦略を定義できることに注目してください。Employee クラスは、自分がどのようにソートされるかについて何も知る必要はありません。

チートシート

Comparatorインターフェースを使用すると、元のクラスを変更せずにオブジェクトをソートするための外部比較ロジックを作成できます。これは、複数のソートオプションが必要な場合に便利です。

Comparatorは、compare()メソッドを実装することで、同じ型の2つのオブジェクトを比較します。

import java.util.Comparator;

class NameComparator implements Comparator<Person> {
    @Override
    public int compare(Person p1, Person p2) {
        return p1.getName().compareTo(p2.getName());
    }
}

コンパレータをソートメソッドに渡します。

Collections.sort(people, new NameComparator());

Comparatorは関数型インターフェースであるため、ラムダ式を使用して簡潔なコードを記述できます。

Collections.sort(people, (p1, p2) -> p1.getName().compareTo(p2.getName()));

数値を比較する場合は、安全な比較のためにDouble.compare()のようなラッパークラスのメソッドを使用します。

class AgeComparator implements Comparator<Person> {
    @Override
    public int compare(Person p1, Person p2) {
        return p1.getAge() - p2.getAge();
    }
}

主な違い: Comparableはクラス自体の中で1つの自然な順序を定義しますが、Comparatorは外部で無制限のカスタム順序を定義できる別のクラスです。

自分で試してみよう

import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // 入力から3人の従業員を読み込む
        // 各行の形式: 名前,部署,給与
        String line1 = scanner.nextLine();
        String line2 = scanner.nextLine();
        String line3 = scanner.nextLine();
        
        // TODO: 各行を解析し、Employeeオブジェクトを作成する
        // ヒント: 値を分割するには split(",") を使用する
        
        // TODO: 従業員のArrayListを作成し、3人全員を追加する
        
        // TODO: SalaryComparatorを使用して給与順にソートし、各従業員を出力する
        // ヒント: Collections.sort(list, comparator) を使用する
        
        // TODO: 空行を出力する
        
        // TODO: NameComparatorを使用して名前順にソートし、各従業員を出力する
    }
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン