Java
 Computer >> コンピューター >  >> プログラミング >> Java

JavaにおけるComparableとComparatorの違いを徹底解説

はじめに

Javaでは、コレクション(Listなど)の要素を並べ替える際に、ComparableComparatorという2つのインターフェースを使用できます。どちらもソートのためのインターフェースですが、役割や使い方には明確な違いがあります。

Comparableはjava.langパッケージに属し、「自分自身(this)」と引数で渡された1つのオブジェクトを比較することで、クラス固有の自然順序付けを定義します。一方、Comparatorはjava.utilパッケージに属し、比較対象となる2つのオブジェクトを受け取り、ソートのロジックを外部から柔軟に指定できるのが特徴です。

ComparableとComparatorの比較表

No.項目ComparableComparator
1メソッドcompareTo(Object a)compare(Object o1, Object o2)
2ソート方法Collections.sort(List) を使用Collections.sort(List, Comparator) を使用
3ソート順序単一のソート順序(自然順序)のみ定義可能複数のソート順序を定義可能
4所属パッケージjava.langjava.util

使い分けのポイント

  • Comparable:クラス自体に「標準の並び順」を持たせたい場合に実装します。社員番号順や日付順のように、そのクラスにとって最も自然な順序が1つに決まっているケースに向いています。
  • Comparator:同じデータでも「名前順」「価格順」「評価順」など、状況に応じて複数の並び替え基準を使い分けたい場合に便利です。対象クラスを修正せずに済むため、既存コードへの影響もありません。

また、Java 8以降ではラムダ式や Comparator.comparing() といったファクトリメソッドを活用することで、Comparatorをより簡潔に記述できます。

Comparableの実装例

以下の例では、LaptopクラスがComparableを実装し、RAM容量を基準とした自然順序付けを定義しています。

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class ComparableExample {
    public static void main(String[] args) {
        List<Laptop> laptopList = new ArrayList<>();
        laptopList.add(new Laptop("HCL", 16, 800));
        laptopList.add(new Laptop("Apple", 8, 100));
        laptopList.add(new Laptop("Dell", 4, 600));

        Collections.sort(laptopList);

        for (Laptop lap : laptopList) {
            System.out.println(lap.getRam());
        }
    }
}

class Laptop implements Comparable<Laptop> {
    String name;
    int ram;
    int price;

    public Laptop(String name, int ram, int price) {
        this.name = name;
        this.ram = ram;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public int getRam() {
        return ram;
    }

    public void setRam(int ram) {
        this.ram = ram;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }

    @Override
    public int compareTo(Laptop o) {
        // RAM容量を昇順で比較
        return Integer.compare(this.ram, o.getRam());
    }
}

出力結果

4
8
16

RAM容量の小さい順(昇順)に並んでいることが確認できます。

Comparatorの実装例

次の例では、Comparatorを使って名前順にソートしています。比較ロジックをラムダ式として外部から渡せる点が、Comparatorの大きな強みです。

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class Laptop implements Comparator<Laptop> {
    String name;
    int ram;
    int price;

    public Laptop(String name, int ram, int price) {
        this.name = name;
        this.ram = ram;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public int getRam() {
        return ram;
    }

    public void setRam(int ram) {
        this.ram = ram;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }

    @Override
    public int compare(Laptop o1, Laptop o2) {
        return Integer.compare(o1.getRam(), o2.getRam());
    }

    public static void main(String[] args) {
        List<Laptop> laptopList = new ArrayList<>();
        laptopList.add(new Laptop("HCL", 16, 800));
        laptopList.add(new Laptop("Apple", 8, 100));
        laptopList.add(new Laptop("Dell", 4, 600));

        // 名前順でソートするComparator(ラムダ式で記述)
        Comparator<Laptop> com =
                (Laptop o1, Laptop o2) -> o1.getName().compareTo(o2.getName());
        Collections.sort(laptopList, com);

        for (Laptop lap : laptopList) {
            System.out.println(lap.getName());
        }
    }
}

出力結果

Apple
Dell
HCL

名前のアルファベット順にソートされていることがわかります。

まとめ

  • Comparable:クラス自身に自然順序を定義するためのインターフェース(compareToメソッドを実装)。
  • Comparator:外部から柔軟にソート基準を指定できるインターフェース(compareメソッドを実装)。
  • 並び順が1つで十分ならComparable、複数の並び順を使い分けたいならComparatorを選ぶのが基本。
  • Java 8以降はラムダ式や Comparator.comparing() を使うことで、Comparatorをより簡潔に書ける。
  1. JavaのIteratorとEnumerationの違いを徹底比較!使い分けのポイントを解説

    はじめに:IteratorとEnumerationとはJavaのコレクションフレームワークには、コレクション内の要素を順番に走査(トラバース)しながらアクセスするための仕組みとして「カーソル」が用意されています。その代表格が Iterator(イテレータ) と Enumeration(列挙) の2つです。両者はどちらもコレクションフレームワークに属しますが、登場した時期と役割が異なります。EnumerationはJDK 1.0から存在する歴史あるインターフェースで、IteratorはJDK 1.2でコレクションフレームワークとともに導入された、より新しいインターフェースです。Enumerati

  2. JavaでのArrayListとHashSetの違いを徹底解説!使い分けのポイントも紹介

    HashSetとArrayListは、どちらもJavaコレクションフレームワークにおいて最も重要なクラスの一つです。それぞれ特徴が異なるため、用途に応じた適切な使い分けが求められます。本記事では、ArrayListとHashSetの主な違いを6つの観点から比較し、実際のサンプルコードとともにわかりやすく解説します。ArrayListとHashSetの違い一覧No.項目ArrayListHashSet1実装インターフェースListインターフェースを実装しています。Setインターフェースを実装しています。2内部構造内部的には配列(動的配列)を使って実装されています。内部的にはHashMapを使って