Code Stack

独自クラスが要素に入ったListのソートを行う

更新日 2025年3月23日

このページでは、List型のソート方法について記載しています。
特にListの中身が独自クラスの場合について記載しています。



独自クラスが要素に入ったListのソートを行う


シンプルなListのソート

まずは普通にListをソートする方法について確認したいと思います。
以下のコードは、Listの中身がString型の場合にソートを行う例です。

              List<String> list = Arrays.asList("banana", "apple", "orange");
    
    // 昇順ソート
    list.sort(Comparator.naturalOrder());
    // ソート結果
    // apple
    // banana
    // orange
    
    // 降順ソート
    list.sort(Comparator.reverseOrder());
    // ソート結果
    // orange
    // banana
    // apple
}
        

このように、Listの中身がString型の場合は、Comparator.naturalOrder()を使って昇順ソート、
Comparator.reverseOrder()を使って降順ソートを行うことができます。


ちなみに、Collections.sort()を使ってソートする方法もあります。
以下のコードは、Collectionsを使ってListをソートする例です。

              List<String> list = Arrays.asList("banana", "apple", "orange");
    
    // 昇順ソート
    Collections.sort(list);

    // 降順ソート
    Collections.sort(list, Comparator.reverseOrder());

        

ソート結果はこちらも同じ結果が出力されます。
Collection.sort()の方はjava 1.2から存在しており、List.sort()はjava 8から追加されたメソッドです。
どちらを使っても問題ありませんが、List.sort()の方がCollectionsを呼び出さなくて良く、
新しいメソッドのため、List.sort()を使ってこの記事では使用しています。




独自クラスが要素に入ったListのソートを行う


ここからは、独自クラスを含むListのソート方法について説明します。
独自クラスを含むListをソートする場合は、先ほど使用したComparator型のラムダ式を実装する必要があります。
以下にコードの例を記載します。

              // 独自クラス
    class Fruit {
        String name;
        int price;
        String getName() { 
            return name; 
        }
        int getPrice() { 
            return price; 
        }
        Fruit(String name, int price) {
            this.name = name;
            this.price = price;
        }
    }
    
    List<Fruit> list = Arrays.asList(new Fruit("banana", 100), new Fruit("apple", 150), new Fruit("orange", 120));

    // Fruitクラスのnameで昇順ソート Comparator.comparing()でnameを比較してソートされます
    Comparator<Fruit> comparator = Comparator.comparing(Fruit::getName);
    // Comparator<Fruit> comparator = Comparator.comparing(x -> x.getName()); のラムダ式でもOK

    list.sort(comparator);
    // ソート結果
    // name:apple, price:150
    // name:banana, price:100
    // name:orange, price:120

    // Fruitクラスのnameで降順ソート 降順にする場合はreversed()を使います
    Comparator<Fruit> reverseComparator = Comparator.comparing(Fruit::getName).reversed();
    list.sort(reverseComparator);
    // ソート結果
    // name:orange, price:120
    // name:banana, price:100
    // name:apple, price:150

    // Fruitクラスのpriceで昇順ソート
    Comparator<Fruit> priceComparator = Comparator.comparing(Fruit::getPrice);
    list.sort(priceComparator);
    // ソート結果
    // name:banana, price:100
    // name:orange, price:120
    // name:apple, price:150

        

コード例では、Fruitクラスを作成し、nameとpriceを持つクラスを作成しています。
その後、Comparator.comparing()に比較対象となるフィールド(getName()やgetPrice())を指定して、
list.sort()でソートを行っています。


Comparator型のラムダ式の実装をカスタマイズすることで複雑なソートも可能です。
例えば、複数の要素でソートしたい場合はComparator.comparing()の後にthenComparing()を使って比較することができます。
nameが同じ場合はpriceの降順で比較することができます。

              List<Fruit> list = 
    Arrays.asList(new Fruit("banana", 100), new Fruit("apple", 150), new Fruit("orange", 120), new Fruit("apple", 300));

    // nameで昇順ソート、nameが同じ場合はpriceの降順ソート
    Comparator<Fruit> customComparator = Comparator.comparing(Fruit::getName)
                                                    .thenComparing(Fruit::getPrice, Comparator.reverseOrder());
    list.sort(customComparator);
    // ソート結果
    // name:apple, price:300
    // name:apple, price:150
    // name:banana, price:100
    // name:orange, price:120

        

このように複数のフィールドを比較することができます。
昇順、降順を指定する際に1点、注意点があります。
昇順、降順は以下のようにも指定できます。

              // nameで昇順ソート、nameが同じ場合はpriceの降順ソート
    Comparator<Fruit> customComparator = Comparator.comparing(Fruit::getName)
                                                    .thenComparing(Fruit::getPrice)
                                                    .reversed();
    list.sort(customComparator);
    // ソート結果
    // name:orange, price:120
    // name:banana, price:100
    // name:apple, price:300
    // name:apple, price:150

        

このように、Comparator.comparing()の後にreversed()を使って降順にすることもできます。
ただし、thenComparing()の後にreversed()を使うと、そこまでに記載されている要素のソートも
逆順になってしまうので、注意が必要です。
昇順、降順が混在する場合は、1つ目のコードのような書き方で指定するのが良いかと思います。



リストの要素にNullが含まれる場合

リストにNullが含まれる場合、ソートを行うとNullPointerExceptionが発生します。
そのため、Nullを含むリストをソートする際は、Nullを扱うためのComparatorを使用することが重要です。
以下にその方法を示します。

              List<Fruit> list = Arrays.asList(new Fruit("banana", 100), new Fruit("apple", 150), new Fruit("orange", 120) ,new Fruit(null, 500));

    Comparator<Fruit> customComparator = Comparator.comparing(Fruit::getName, Comparator.nullsLast(Comparator.naturalOrder()))
                                                    .thenComparing(Fruit::getPrice);
    list.sort(customComparator);


        

上記のコードでは、Comparator.nullsLast()を使用して、Nullをリストの最後に移動させています。
このようにして、Nullを含むリストでも安全にソートを行うことができます。

さらに、Comparator.nullsFirst()を使用することで、Nullをリストの最初に移動させることも可能です。