Javaで自作クラスをソートする3通りの方法【Java8】
Javaで自前のクラスをソートするにはどうしたらよいか紹介します。Javaで配列やコレクションのソートを行うには主に3通りの方法があります。Java8以降ならばラムダ式がもっとも簡潔に書けます。それでは見ていきましょう。
1. ラムダ式を用いる方法(Java8以降):
自作クラスのPerson型を年齢順でソーティングします。
import java.util.ArrayList; class Person{ int age; String name; public Person( int a, String n ){ age = a; name = n; } public String toString(){ return name + ":" + Integer.toString(age); } } class Main{ public static void main(String[] av){ ArrayList<Person> al = new ArrayList<Person>(){ { add( new Person( 11, "katsuo" ) ); add( new Person( 24, "sazae" ) ); add( new Person( 9, "wakame" ) ); } }; al.sort((a,b)-> a.age - b.age ); /*ラムダ式*/ System.out.println( al ); } }
実行結果
[wakame:9, katsuo:11, sazae:24]
ラムダ式で書くと非常に簡潔にソートの方式を指定できていることが分かります。ラムダ式は右辺が一行の場合、それが返り値となります。ここで注意しておきたいのは、返り値はboolean型ではなく、int型ということです。
逆順でソートしたかったときは以下のように書くだけです。簡単ですね。
al.sort( (a,b)-> b.age - a.age );
もし、年齢順ではなく、名前順でソートしたい時はどうすればよいでしょうか?
String型のメソッドcompareToをラムダ式内で呼び出します。
al.sort( (a,b)->a.name.compareTo( b.name ) );
実行結果
[katsuo:11, sazae:24, wakame:9]
2. Comparableインターフェースを実装する方法:
ComparableインターフェースのcompareToメソッドをオーバーライドして実装する方法です。
import java.util.ArrayList; import java.util.Collections; class Person implements Comparable<Person>{ int age; String name; public Person( int a, String n ){ age = a; name = n; } public String toString(){ return name + ":" + Integer.toString(age); } @Override public int compareTo( Person p ){ return this.age - p.age; } } class Main{ public static void main(String[] av){ ArrayList<Person> al = new ArrayList<>(); al.add( new Person( 11, "katsuo" ) ); al.add( new Person( 24, "sazae" ) ); al.add( new Person( 9, "wakame" ) ); Collections.sort( al ); System.out.println( al ); } }
実行結果
[wakame:9, katsuo:11, sazae:24]
Comparableインターフェースはjava.langパッケージに属しているので、importすることなく利用できます。compareToの返り値はラムダ式と同様にint型でなければなりません。ここで、Comparableに型名を指定しましょう。指定しない場合、compareToの引数にObject型をとらなければなりません。キャストの手間もあり、面倒です。
Java8以前はArrayListにsort関数が実装されていない点に注意です。
3. Comparatorを使う方法:
import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; class Person{ int age; String name; public Person( int a, String n ){ age = a; name = n; } public String toString(){ return name + ":" + Integer.toString(age); } } class Main{ public static void main(String[] av){ ArrayList<Person> al = new ArrayList<>(); al.add( new Person( 11, "katsuo" ) ); al.add( new Person( 24, "sazae" ) ); al.add( new Person( 9, "wakame" ) ); Collections.sort( al, new Comparator<Person>(){ @Override public int compare(Person a, Person b){ return a.age - b.age; } }); System.out.println( al ); } }
Comparator型を無名クラスで生成しています。ここでも、Comparatorに型指定をしておきましょう。実はラムダ式と内部的にやっていることは一緒ですが、コードが長くなってします。Java8以降であれば、ラムダ式で書いた方がコードの見通しもよくなると思います。
配列ではどうするか:
最後に配列でのソートについて、見ていきます。コレクションとほぼ同じです。
import java.util.Arrays; class Person{ int age; String name; public Person( int a, String n ){ age = a; name = n; } public String toString(){ return name + "\t" + Integer.toString(age); } } class Main{ public static void main(String[] av){ Person[] arr = {new Person(11,"katsuo"), new Person(24, "sazae"), new Person(9,"wakame")}; Arrays.sort( arr, (a,b)-> a.age - b.age ); for ( Person p : arr ){ System.out.println( p ); } } }
実行結果
wakame 9 katsuo 11 sazae 24
違いは以下の部分だけです
Arrays.sort( arr, (a,b)-> a.age - b.age );
ラムダ式以外の方法でもまったく変わりません。
Javaプログラマーなら習得しておきたい Java SE 8 実践プログラミング
Java 最強リファレンス
JavaFX & Java8プログラミング―Javaによる新しいGUIプログラミング入門