【Java Stream API 超入門】sortedメソッドを使ってオブジェクトをソートする方法

こんにちは。大城です。
 
本ブログでは、Java SE 8で追加されたStream APIについて、初心者向けに解説していきます。前回のブログでは、2重Listを1重に直すflatMapと重複を削除するdistinctについて説明しました。
 
中間処理3回目の今回は、ソートを行うsortedについて解説していきます。

環境

OS
Windows10
Java
Java8

Comparableを実装しているオブジェクトをソートするsorted()

IntegerやStringのような、java.lang.Comparableを実装しているクラスは簡単にソートすることができます。例をご覧ください。

public class Main {
	public static void main(String[] args) {

		List<Integer> intList = Arrays.asList(3, 1, 4, 5);

		System.out.println("------ ソートする前 ------");
		intList.stream()
			.forEach(e -> System.out.println(e));

		System.out.println("------ sorted()メソッドによってソートした結果 ------");
		intList.stream()
			.sorted() // ソートの実施
			.forEach(e -> System.out.println(e));

		List<String> strList = Arrays.asList("Tokyo", "Chiba", "Saitama", "Kanagawa", "Gunma");

		System.out.println("------ ソートする前 ------");
		strList.stream()
			.forEach(e -> System.out.println(e));

		System.out.println("------ sorted()メソッドによってソートした結果 ------");
		strList.stream()
			.sorted() // ソートの実施
			.forEach(e -> System.out.println(e));
	}
}

実行結果
------ ソートする前 ------
3
1
4
5
------ sorted()メソッドによってソートした結果 ------
1
3
4
5
------ ソートする前 ------
Tokyo
Chiba
Saitama
Kanagawa
Gunma
------ sorted()メソッドによってソートした結果 ------
Chiba
Gunma
Kanagawa
Saitama
Tokyo

Integerはその大きさで、Stringは辞書式順序でそれぞれソートされていることがわかります。このように、Comparableを実装しているクラスは、Streamを取得してsorted()メソッドを実行するだけでソートを実施することができます。

Comprableを実装していないオブジェクトのソート

続いて、自作クラスなどのようなComparableを実装していないクラスをソートするする方法について解説します。この場合は、オブジェクトからComparableな値を取り出して比較するComparatorを生成して、sortedに引数として渡します。例をご覧ください。

class City {
	private String name;
	private int population;

	public City(String name, int population) {
		this.name = name;
		this.population = population;
	}

	public String getName() {
		return name;
	}

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

	public int getPopulation() {
		return population;
	}

	public void setPopulation(int population) {
		this.population = population;
	}
}

public class Main {
	public static void main(String[] args) {

		List<City> cityList = new ArrayList<> (Arrays.asList(
			new City("Bunkyo-ku", 219724),
			new City("Taito-ku", 198073),
			new City("Chiyoda-ku", 58406),
			new City("Shinjuku-ku", 333560)
		));

		System.out.println("------ ソートする前 ------");
		cityList.stream()
			.forEach(e -> System.out.println(e.getName() + "\t:" + e.getPopulation() + "人"));

		System.out.println("------ nameで生成したComparatorでソートを実施 ------");
		Comparator<City> nameComp = Comparator.comparing(e -> e.getName()); // CityクラスのプロパティnameによってComparatorを生成
		cityList.stream()
			.sorted(nameComp) // nameで生成したComparatorでソートを実施
			.forEach(e -> System.out.println(e.getName() + "\t:" + e.getPopulation() + "人"));
	}
}

実行結果

------ ソートする前 ------
Bunkyo-ku       :219724人
Taito-ku        :198073人
Chiyoda-ku      :58406人
Shinjuku-ku     :333560人
------ nameで生成したComparatorでソートを実施 ------
Bunkyo-ku       :219724人
Chiyoda-ku      :58406人
Shinjuku-ku     :333560人
Taito-ku        :198073人

Comparatorは、Comparator.comparing()にラムダ式を渡して生成します。この際、オブジェクトからComparableな値を返すようなラムダ式を渡します。上記の例ではCityクラスのString型のプロパティであるnameを返すラムダ式e -> e.getName()を渡しています。
 
これによって、Streamはnameプロパティによって辞書式にソートされる結果となっているのです。上記の他に、City.getName().length()や、City.getPopulation()もComparableな値を返すので、これらによるソートの例を下記に記します。
class City {
	private String name;
	private int population;

	public City(String name, int population) {
		this.name = name;
		this.population = population;
	}

	public String getName() {
		return name;
	}

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

	public int getPopulation() {
		return population;
	}

	public void setPopulation(int population) {
		this.population = population;
	}
}

public class Main {
	public static void main(String[] args) {

		List<City> cityList = new ArrayList<> (Arrays.asList(
			new City("Bunkyo-ku", 219724),
			new City("Taito-ku", 198073),
			new City("Chiyoda-ku", 58406),
			new City("Shinjuku-ku", 333560)
		));

		System.out.println("------ ソートする前 ------");
		cityList.stream()
			.forEach(e -> System.out.println(e.getName() + "\t:" + e.getPopulation() + "人"));

		System.out.println("------ nameによってソートした結果 ------");
		cityList.stream()
			.sorted(Comparator.comparing(e -> e.getName()))
			.forEach(e -> System.out.println(e.getName() + "\t:" + e.getPopulation() + "人"));

		System.out.println("------ nameのlengthでソートした結果 ------");
		cityList.stream()
			.sorted(Comparator.comparing(e -> e.getName().length()))
			.forEach(e -> System.out.println(e.getName() + "\t:" + e.getPopulation() + "人"));

		System.out.println("------ poplationでソートした結果 ------");
		cityList.stream()
			.sorted(Comparator.comparing(e -> e.getPopulation()))
			.forEach(e -> System.out.println(e.getName() + "\t:" + e.getPopulation() + "人"));
	}
}

実行結果
------ ソートする前 ------
Bunkyo-ku       :219724人
Taito-ku        :198073人
Chiyoda-ku      :58406人
Shinjuku-ku     :333560人
------ nameによってソートした結果 ------
Bunkyo-ku       :219724人
Chiyoda-ku      :58406人
Shinjuku-ku     :333560人
Taito-ku        :198073人
------ nameのlengthでソートした結果 ------
Taito-ku        :198073人
Bunkyo-ku       :219724人
Chiyoda-ku      :58406人
Shinjuku-ku     :333560人
------ poplationでソートした結果 ------
Chiyoda-ku      :58406人
Taito-ku        :198073人
Bunkyo-ku       :219724人
Shinjuku-ku     :333560人

逆順ソート

上記では昇順ソートについて説明しましたが、最後に降順ソートのやり方も紹介します。

Comparableなオブジェクトの場合

ComparableなオブジェクトはsortedにComparator.reverseOrder()を渡すことで降順ソートすることができます。例をご覧ください。

public class Main {
	public static void main(String[] args) {
 
		List<Integer> intList = Arrays.asList(3, 1, 4, 5);
 
		System.out.println("------ ソートする前 ------");
		intList.stream()
			.forEach(e -> System.out.println(e));
 
		System.out.println("------ sorted(Comparator.reverseOrder())によって降順ソートした結果 ------");
		intList.stream()
			.sorted(Comparator.reverseOrder()) // ソートの実施
			.forEach(e -> System.out.println(e));
 
		List<String> strList = Arrays.asList("Tokyo", "Chiba", "Saitama", "Kanagawa", "Gunma");
 
		System.out.println("------ ソートする前 ------");
		strList.stream()
			.forEach(e -> System.out.println(e));
 
		System.out.println("------ sorted(Comparator.reverseOrder())によって降順ソートした結果 ------");
		strList.stream()
			.sorted(Comparator.reverseOrder()) // ソートの実施
			.forEach(e -> System.out.println(e));
	}
}

実行結果
------ ソートする前 ------
3
1
4
5
------ sorted(Comparator.reverseOrder())によって降順ソートした結果 ------
5
4
3
1
------ ソートする前 ------
Tokyo
Chiba
Saitama
Kanagawa
Gunma
------ sorted(Comparator.reverseOrder())によって降順ソートした結果 ------
Tokyo
Saitama
Kanagawa
Gunma
Chiba

降順にソートできていることがわかります。

Comparableを実装しないオブジェクトの場合

Comparableが実装されていないオブジェクトは、Comparatorに.reversed()を指定します。例をご覧ください。

class City {
	private String name;
	private int population;

	public City(String name, int population) {
		this.name = name;
		this.population = population;
	}

	public String getName() {
		return name;
	}

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

	public int getPopulation() {
		return population;
	}

	public void setPopulation(int population) {
		this.population = population;
	}
}

public class Main {
	public static void main(String[] args) {

		List<City> cityList = new ArrayList<> (Arrays.asList(
			new City("Bunkyo-ku", 219724),
			new City("Taito-ku", 198073),
			new City("Chiyoda-ku", 58406),
			new City("Shinjuku-ku", 333560)
		));

		System.out.println("------ ソートする前 ------");
		cityList.stream()
			.forEach(e -> System.out.println(e.getName() + "\t:" + e.getPopulation() + "人"));

		System.out.println("------ nameによって降順ソートした結果 ------");
		cityList.stream()
			.sorted(Comparator.comparing(e -> ((City)e).getName()).reversed())
			.forEach(e -> System.out.println(e.getName() + "\t:" + e.getPopulation() + "人"));

		System.out.println("------ nameのlengthで降順ソートした結果 ------");
		cityList.stream()
			.sorted(Comparator.comparing(e -> ((City)e).getName().length()).reversed())
			.forEach(e -> System.out.println(e.getName() + "\t:" + e.getPopulation() + "人"));

			System.out.println("------ poplationで降順ソートした結果 ------");
			cityList.stream()
				.sorted(Comparator.comparing(e -> ((City)e).getPopulation()).reversed())
				.forEach(e -> System.out.println(e.getName() + "\t:" + e.getPopulation() + "人"));
	}
}

実行結果
------ ソートする前 ------
Bunkyo-ku       :219724人
Taito-ku        :198073人
Chiyoda-ku      :58406人
Shinjuku-ku     :333560人
------ nameによって降順ソートした結果 ------
Taito-ku        :198073人
Shinjuku-ku     :333560人
Chiyoda-ku      :58406人
Bunkyo-ku       :219724人
------ nameのlengthで降順ソートした結果 ------
Shinjuku-ku     :333560人
Chiyoda-ku      :58406人
Bunkyo-ku       :219724人
Taito-ku        :198073人
------ poplationで降順ソートした結果 ------
Shinjuku-ku     :333560人
Bunkyo-ku       :219724人
Taito-ku        :198073人
Chiyoda-ku      :58406人

それぞれ降順ソートができていることがわかります。注意点として、comparingに渡すラムダ式では((City)e).getName()のようにキャストを行うなどして明示的に型を指定しなければなりません。
 
詳細は割愛しますが、型を推論できる根拠がないとコンパイルエラーが発生します。

まとめ

いかがでしたか。
 
Streamのソートを行いたいときはsorted()を実行するだけで良く、非常にわかりやすいかと思います。次回では、Streamを用いた処理の略記やラムダ式・メソッド参照について解説していこうと思います。
 
それでは、また。
 
 
 
 
《関連記事》

記事をシェア
MOST VIEWED ARTICLES