Java8 で追加された Steam API により、これまで何行にも渡って書かれ、冗長になりがちだったソート処理を簡潔に記述することが可能になりました。
この記事では、リストなどのコレクションを、Steam API とラムダ式を使ってソートする方法を解説します。
基本のソート
最初は、int や char などの基本データ型(プリミティブ型)のコレクションをソートして、Steam API でのソートのイメージを掴みましょう。
次のサンプルコードは、数値のリストを昇順に並べる例です。Steam API では、Stream#sort メソッド使用してコレクションのソートを行っていきます。
//↓以下の import が必要
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static java.util.Comparator.*;
List<Integer> list = new ArrayList<Integer>(Arrays.asList(30, 20, 50, 10));
list.sort(naturalOrder());
// 10, 20, 30, 50
降順にソートする場合は、メソッドの引数に reverseOrder を指定します。
list.sort(Comparator.reverseOrder())
文字列(String)のソート
String 型のリストも、基本データ型の時と同様に、値を格納したリストに対しStream#sort メソッドを呼び出せば、文字コード順にソートできます。
String[] strs = {"AA", "aa", "BB", "bb", "CC", "cc"};
List<String> list = Arrays.asList(strs.clone());
list.sort(naturalOrder());
// "AA", "BB", "CC", "aa", "bb", "cc"
通常、文字列のソートを行う場合は、英字は大文字、小文字は区別され、大文字のA-Z →小文字の a-z の順にソートが行われますが、StringクラスのCASEINSENSITIVEORDERを引数に渡すと、大文字、小文字の区別を行わずにソートできます。
実際に試してみましょう。
String[] strs = {"AA", "aa", "BB", "bb", "CC", "cc"};
List<String> list = Arrays.asList(strs.clone());
list.sort(String.CASE_INSENSITIVE_ORDER);
// "AA", "aa", "BB", "bb", "CC", "cc"
オブジェクトのソート
独自に作成したクラスなどのオブジェクトも、任意のキーを指定して、コレクションをソートできます。 オブジェクトをソートする場合は、ソートキーとなるプロパティなどをjava.util.Comparator#comparing で指定します。
単項目のキーでオブジェクトをソート
次のコードは、User クラスのscoreプロパティをキーに、オブジェクトを降順でソートする例です。
List<User> list = new ArrayList<>();
// new User(氏名、ランク、スコア)
list.add(new User("Yamada", 1, 50));
list.add(new User("Sato", 1, 20));
list.add(new User("Hayashi", 2, 10));
list.add(new User("Abe", 2, 40));
//スコアの降順でソート
list.sort(comparing(User::getScore).reversed());
//ソートした結果を表示
for (User user : list) {
System.out.println(String.format("%s:%d", user.getName(), user.getScore()));
}
// Yamada:50
// Abe:40
// Sato:20
// Hayashi:10
また、上のコードは、ラムダ式を使って次のようにも書くことができます。
list.sort(comparing((User x) -> x.getScore()).reversed());
複数キーでのソート
ソートキーが複数ある場合は、thenComparingメソッドを使用してソートキーを複数指定します。次のサンプルコードは、ランクの昇順、スコアの降順でコレクションをソートする例です。
List<User> list = new ArrayList<>();
list.add(new User("Yamada", 1, 50));
list.add(new User("Sato", 1, 20));
list.add(new User("Hayashi", 2, 10));
list.add(new User("Abe", 2, 40));
// ランクの昇順、スコアの降順でリストを並び替え
list.sort(comparing(User::getRank).thenComparing(comparing(User::getScore).reversed()));
for (User user : list) {
System.out.println(String.format("%s rank=%d score=%d",
user.getName(), user.getRank(), user.getScore()));
}
//Yamada rank=1 score=50
//Sato rank=1 score=20
//Abe rank=2 score=40
//Hayashi rank=2 score=10
最後に今回使用した User クラスの定義を載せておきます。
public class User {
//ユーザ名
public String name;
//ランク
public int rank;
//スコア
public int score;
public User(String name, int rank, int score) {
this.name = name;
this.rank = rank;
this.score = score;
}
public String getName() {
return name;
}
public int getRank() {
return rank;
}
public int getScore() {
return score;
}
}
まとめ
Java8 で追加された Steam API で、コレクションをソートする方法を解説しました。
Steam API をうまく活用することで、これまで冗長的になりがちだった Java のコードを、よりシンプルに分かりやすく記述することが可能になりました。
Steam API については、以下の記事でも紹介しているため、こちらもご覧ください。
Java8 以前は、ソートするオブジェクトに Comparable インタフェースを実装する必要がありましたが、Steam API の登場によって、非常にシンプルなコードでソートが可能になりました。