前回はIteratorとIterableの仕組みを理解し、自作クラスに拡張for文対応を実装しました。 今回は「Comparator(コンパレータ)」について解説します。 Collections.sort() や List.sort() でリストをソートしてきましたが、自分でソートの基準を定義することで、複雑な並び替えも自由に実現できるようになります。
Comparatorとは
Collections.sort() はデフォルトで「自然順序」(数値なら昇順、文字列なら辞書順)でソートします。しかし「年齢の降順」「名前の長さ順」「複数の条件を組み合わせた順」など、独自のソート基準が必要な場合があります。
Comparator<T> は2つの要素を比較して順序を決めるためのインターフェースです。
public interface Comparator<T> {
int compare(T o1, T o2);
}
compare メソッドは以下のルールで整数を返します。
負の値 → o1がo2より前(小さい)
0 → o1とo2は同じ順序
正の値 → o1がo2より後(大きい)
ラムダ式を使うと Comparator を1行で書けます。
サンプルコード(基本的なComparatorの使い方)
ファイル作成
「Java34」フォルダに ComparatorTest.java という名前でファイルを作成します

コード入力
以下のコードを入力します。
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class ComparatorTest {
public static void main(String[] args) {
List<String> names = new ArrayList<>();
names.add("ぱんまる");
names.add("たろう");
names.add("はなこ");
names.add("あいこ");
names.add("けんじ");
// デフォルトソート(辞書順)
Collections.sort(names);
System.out.println("辞書順: " + names);
// 文字数の少ない順
names.sort(Comparator.comparingInt(String::length));
System.out.println("文字数(昇順): " + names);
// 文字数の多い順(reversed)
names.sort(Comparator.comparingInt(String::length).reversed());
System.out.println("文字数(降順): " + names);
// 数値リストを降順にソート
List<Integer> numbers = new ArrayList<>(List.of(5, 2, 8, 1, 9, 3));
numbers.sort(Comparator.reverseOrder());
System.out.println("数値(降順): " + numbers);
// ラムダ式で独自比較
List<String> fruits = new ArrayList<>(List.of("banana", "apple", "cherry", "kiwi"));
fruits.sort((a, b) -> a.length() - b.length()); // 文字数で昇順
System.out.println("果物(文字数順): " + fruits);
}
}

コンパイル
javac ComparatorTest.java

実行
java ComparatorTest
実行結果は次のようになります。
辞書順: [あいこ, たろう, はなこ, ぱんまる, けんじ]
文字数(昇順): [たろう, はなこ, あいこ, けんじ, ぱんまる]
文字数(降順): [ぱんまる, たろう, はなこ, あいこ, けんじ]
数値(降順): [9, 8, 5, 3, 2, 1]
果物(文字数順): [kiwi, apple, banana, cherry]

サンプルコード(複数条件でのソート)
自作クラスのオブジェクトを複数条件でソートする例を作ります。
ファイル作成
「Java34」フォルダに Student.java、ComparatorAdvTest.java という名前でファイルを作成します

コード入力
Student.java に以下のコードを入力します。
public class Student {
String name;
int score;
int age;
Student(String name, int score, int age) {
this.name = name;
this.score = score;
this.age = age;
}
@Override
public String toString() {
return name + "(点数:" + score + ", 年齢:" + age + ")";
}
}

ComparatorAdvTest.java に以下のコードを入力します。
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
public class ComparatorAdvTest {
public static void main(String[] args) {
List<Student> students = new ArrayList<>();
students.add(new Student("ぱんまる", 85, 20));
students.add(new Student("たろう", 90, 22));
students.add(new Student("はなこ", 85, 19));
students.add(new Student("けんじ", 72, 21));
students.add(new Student("あいこ", 90, 20));
System.out.println("--- 元の順番 ---");
students.forEach(System.out::println);
// 点数の降順
students.sort(Comparator.comparingInt((Student s) -> s.score).reversed());
System.out.println("\n--- 点数(降順) ---");
students.forEach(System.out::println);
// 点数の降順 → 同点なら年齢の昇順
students.sort(
Comparator.comparingInt((Student s) -> s.score).reversed()
.thenComparingInt(s -> s.age)
);
System.out.println("\n--- 点数(降順) → 年齢(昇順) ---");
students.forEach(System.out::println);
// 点数の降順 → 同点なら名前の辞書順
students.sort(
Comparator.<Student, Integer>comparing(s -> s.score).reversed()
.thenComparing(s -> s.name)
);
System.out.println("\n--- 点数(降順) → 名前(辞書順) ---");
students.forEach(System.out::println);
}
}

コンパイル
javac Student.java ComparatorAdvTest.java

実行
java ComparatorAdvTest
実行結果は次のようになります。
--- 元の順番 ---
ぱんまる(点数:85, 年齢:20)
たろう(点数:90, 年齢:22)
はなこ(点数:85, 年齢:19)
けんじ(点数:72, 年齢:21)
あいこ(点数:90, 年齢:20)
--- 点数(降順) ---
たろう(点数:90, 年齢:22)
あいこ(点数:90, 年齢:20)
ぱんまる(点数:85, 年齢:20)
はなこ(点数:85, 年齢:19)
けんじ(点数:72, 年齢:21)
--- 点数(降順) → 年齢(昇順) ---
あいこ(点数:90, 年齢:20)
たろう(点数:90, 年齢:22)
はなこ(点数:85, 年齢:19)
ぱんまる(点数:85, 年齢:20)
けんじ(点数:72, 年齢:21)
--- 点数(降順) → 名前(辞書順) ---
あいこ(点数:90, 年齢:20)
たろう(点数:90, 年齢:22)
ぱんまる(点数:85, 年齢:20)
はなこ(点数:85, 年齢:19)
けんじ(点数:72, 年齢:21)

コードの解説
Comparator.comparingInt(String::length) は文字列の長さを比較基準にするComparatorをシンプルに作ります。reversed() で逆順に、Comparator.reverseOrder() で自然順の逆順にできます。ラムダ式 (a, b) -> a.length() - b.length() のように直接比較ロジックを書くこともできます。
thenComparingInt() と thenComparing() は「最初の比較条件が同じだった場合に適用する第2・第3の条件」を追加するメソッドです。メソッドチェーンでつなげることで、複数の優先順位を持つソートを簡潔に表現できます。
students.forEach(System.out::println) の System.out::println は「メソッド参照」と呼ばれる書き方で、ラムダ式 s -> System.out.println(s) と同じ意味です。以前学んだラムダ式のさらに短い表現です。
まとめ
Comparator を使うことで、デフォルトのソート順以外の独自の並び替え基準を定義できます。Comparator.comparingInt() や reversed() でシンプルに基準を作り、thenComparing() で複数条件を組み合わせるという流れを覚えておきましょう。ラムダ式やメソッド参照との組み合わせで、コードをすっきりと書けます。成績順・日付順・複合条件など、実際のアプリ開発でソートが必要な場面はとても多いので、ぜひ活用してみてください。
2026/07/25(土) ぱんまる


コメント