Javaのラムダ式sorted完全ガイド!Comparator・compareTo・複数条件・文字列の並び替えを理解しよう
生徒
「ラムダ式って便利そうですが、配列やリストを並び替えるときにも使えるんですか?」
先生
「もちろんです。sortedメソッドを使うと、Javaのコレクションをラムダ式で簡単にソートできますよ。」
生徒
「文字列とか複数の条件でも並び替えできますか?」
先生
「できますよ。ComparatorやcompareToを組み合わせることで、文字列のソートや複数条件のソートも自在です。具体例を見ながら学んでいきましょう!」
1. Javaのラムダ式とsortedメソッドの基本
Javaでは、Stream APIとラムダ式を組み合わせて、配列やリストを簡単に並び替えることができます。sorted()メソッドは、Java 8以降で追加された便利なメソッドで、リストの要素を昇順や降順に並び替えるのに使います。
例えば、数値のリストを昇順に並び替えるには以下のように書きます。
import java.util.Arrays;
import java.util.List;
public class SortedExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(5, 1, 8, 3);
numbers.stream()
.sorted()
.forEach(System.out::println);
}
}
このコードでは、sorted()メソッドを使ってList内の整数を昇順に並び替えています。
2. Comparatorを使ったカスタムソート
JavaのComparatorインターフェースを使うと、自分で並び順のルールを定義できます。ラムダ式と組み合わせることで、ソート処理が非常に簡単になります。
以下は、文字列の長さで並び替える例です。
import java.util.Arrays;
import java.util.List;
import java.util.Comparator;
public class LengthSortExample {
public static void main(String[] args) {
List<String> words = Arrays.asList("apple", "banana", "kiwi", "cherry");
words.stream()
.sorted((a, b) -> Integer.compare(a.length(), b.length()))
.forEach(System.out::println);
}
}
このコードでは、文字列の長さを比較して、短い順に並び替えています。
3. compareToで文字列を辞書順にソート
Javaでは、Stringクラスに実装されているcompareToメソッドを使って、文字列の辞書順ソートが可能です。
import java.util.Arrays;
import java.util.List;
public class CompareToExample {
public static void main(String[] args) {
List<String> fruits = Arrays.asList("orange", "apple", "banana", "grape");
fruits.stream()
.sorted((a, b) -> a.compareTo(b))
.forEach(System.out::println);
}
}
compareToは自然順(アルファベット順)でソートを行います。
4. 文字列の降順に並び替えるには
文字列をアルファベット順の逆(降順)にしたいときは、Comparator.reverseOrder()を使うと便利です。
import java.util.Arrays;
import java.util.List;
import java.util.Comparator;
public class ReverseOrderExample {
public static void main(String[] args) {
List<String> items = Arrays.asList("zebra", "apple", "monkey", "banana");
items.stream()
.sorted(Comparator.reverseOrder())
.forEach(System.out::println);
}
}
このように、昇順・降順を切り替えるのも簡単です。
5. 複数条件でソートする方法
複数の条件で並び替えたい場合も、Javaのラムダ式+Comparatorを組み合わせると簡単です。例えば、名前の長さで昇順に並び替えたあと、同じ長さなら辞書順に並び替えるといったケースです。
import java.util.Arrays;
import java.util.List;
import java.util.Comparator;
public class MultiConditionSort {
public static void main(String[] args) {
List<String> names = Arrays.asList("Ken", "Alice", "Bob", "Eve", "Tom");
names.stream()
.sorted(Comparator
.comparingInt(String::length)
.thenComparing(String::compareTo))
.forEach(System.out::println);
}
}
thenComparingを使うことで、条件を複数組み合わせることができます。
6. sortedはListにも使える?
もちろんです。stream()を使えば、ListやArrayListなど、コレクションであれば何にでも適用できます。並び替えたあと、新しいリストとして取得したい場合はcollect(Collectors.toList())を使いましょう。
import java.util.*;
import java.util.stream.Collectors;
public class SortedToListExample {
public static void main(String[] args) {
List<String> animals = Arrays.asList("dog", "cat", "tiger", "lion");
List<String> sortedAnimals = animals.stream()
.sorted()
.collect(Collectors.toList());
System.out.println(sortedAnimals);
}
}
7. Comparator.naturalOrder()とComparator.reverseOrder()の使い分け
Comparator.naturalOrder()は昇順(小さい順・アルファベット順)、Comparator.reverseOrder()は降順(大きい順・逆順)にソートするための定番メソッドです。
特にTreeSetやPriorityQueueなどでも活用されるので覚えておきましょう。
8. nullを含む要素をソートするには
Javaでは、nullを含むリストをソートするとNullPointerExceptionが発生することがあります。その対策として、Comparator.nullsFirstやComparator.nullsLastを使うと安全です。
import java.util.*;
import java.util.stream.Collectors;
public class NullSortExample {
public static void main(String[] args) {
List<String> data = Arrays.asList("alpha", null, "bravo", "charlie");
List<String> sorted = data.stream()
.sorted(Comparator.nullsLast(Comparator.naturalOrder()))
.collect(Collectors.toList());
System.out.println(sorted);
}
}
まとめ
ここまでJavaのラムダ式とStreamのsortedメソッドについて、昇順ソートや降順ソート、Comparatorを使ったカスタムソート、compareToによる文字列の辞書順ソート、複数条件での並び替え、nullを含むリストの安全なソート方法など、実務でもよく使うテクニックをひと通り確認してきました。配列やリストの並び替え処理はどのプログラミング言語でも基本となる重要な分野ですが、Javaではラムダ式とStream APIを組み合わせることで、従来のCollections.sortやfor文を使ったソート処理よりも、直感的で読みやすいコードを書けるようになります。特にsortedメソッドは、ストリームの途中に自然な形でソート処理を挿入できるので、フィルタリングやマッピングと組み合わせたデータ加工の流れをきれいに表現できる点が大きな魅力です。
また、Comparatorを使ったカスタムソートでは、整数や文字列といった基本的な型だけでなく、独自クラスのオブジェクトも柔軟に並び替えられることを学びました。文字列の長さでソートしたり、名前と年齢のように複数のフィールドを組み合わせて複数条件ソートを行ったりすることで、ビジネスロジックに合わせた並び順を自在に表現できるようになります。compareToを使った辞書順ソートや、Comparator.naturalOrderとComparator.reverseOrderの使い分けを理解しておけば、文字列や数値の基本的な昇順・降順の切り替えも迷わずに書けるでしょう。これらの基礎を押さえることで、Javaのソート処理に関する多くのパターンに対応できるようになります。
さらに、実務ではnullを含むリストを扱う場面も少なくありません。そのような場合にComparator.nullsFirstやComparator.nullsLastを利用すると、NullPointerExceptionを避けつつ、nullの位置も制御しながら安全にソートできることを解説しました。こうした細かな部分を意識しておくことで、予期しない例外を減らし、安定したプログラムを実装することができます。また、sortedを使って一時的にストリーム内で並び替えるだけでなく、collect(Collectors.toList())と組み合わせて、新しいリストとして結果を受け取るパターンも、多くの場面で応用できる重要な基本形です。
Javaのラムダ式を使ったソート処理は、一見すると記号が多くて難しく感じるかもしれませんが、sorted、Comparator、compareTo、thenComparing、naturalOrder、reverseOrder、nullsFirst、nullsLastといったキーワードの役割と組み合わせ方に慣れてしまえば、とても表現力の高い道具になります。特に、業務システムで扱うリストやコレクションは、ユーザーに見せる画面の表示順や、レポート出力、ログ解析など、多くの場面で「どの順番で並べるか」が重要になります。そのときに、条件に合わせて柔軟にソートできることは、Javaエンジニアとして大きな強みになります。
これからJavaの勉強を進めていくうえでは、まずは基本的な昇順ソート、降順ソートから手を動かして試してみて、次に文字列の長さや複数条件での並び替え、nullを含むケースなど、少しずつパターンを広げていくと、自分の中で整理しやすくなります。ラムダ式やStream APIは、最初は慣れが必要ですが、使いこなせるようになると、コードの見通しがよくなり、配列やリストの並び替え処理を含むデータ処理全体がすっきりと整理された形で書けるようになります。今回の記事をきっかけに、sortedメソッドとComparatorを使ったソート処理を、自分のアプリケーションやサンプルコードで試しながら、少しずつ定着させていきましょう。
ソート処理をまとめたサンプルプログラム
ここまでの内容を踏まえて、Javaのラムダ式とStreamのsortedを組み合わせたソート処理をひとつのサンプルにまとめてみます。
import java.util.*;
import java.util.stream.Collectors;
import java.util.Comparator;
public class SortedSummaryExample {
public static void main(String[] args) {
// 基本の昇順ソート
List<Integer> numbers = Arrays.asList(5, 1, 8, 3, 2);
List<Integer> asc = numbers.stream()
.sorted()
.collect(Collectors.toList());
System.out.println("昇順ソート:" + asc);
// 降順ソート
List<Integer> desc = numbers.stream()
.sorted(Comparator.reverseOrder())
.collect(Collectors.toList());
System.out.println("降順ソート:" + desc);
// 文字列の長さでソート
List<String> words = Arrays.asList("apple", "banana", "kiwi", "cherry", "fig");
List<String> byLength = words.stream()
.sorted((a, b) -> Integer.compare(a.length(), b.length()))
.collect(Collectors.toList());
System.out.println("長さでソート:" + byLength);
// 文字列を辞書順でソート
List<String> fruits = Arrays.asList("orange", "apple", "banana", "grape");
List<String> lexicographical = fruits.stream()
.sorted(String::compareTo)
.collect(Collectors.toList());
System.out.println("辞書順ソート:" + lexicographical);
// 複数条件ソート(長さ → 辞書順)
List<String> names = Arrays.asList("Ken", "Alice", "Bob", "Eve", "Tom", "Anna");
List<String> multi = names.stream()
.sorted(
Comparator
.comparingInt(String::length)
.thenComparing(String::compareTo)
)
.collect(Collectors.toList());
System.out.println("複数条件ソート:" + multi);
// nullを含むリストを安全にソート
List<String> data = Arrays.asList("alpha", null, "bravo", "charlie", null, "delta");
List<String> withNull = data.stream()
.sorted(
Comparator.nullsLast(
Comparator.naturalOrder()
)
)
.collect(Collectors.toList());
System.out.println("nullを含むソート:" + withNull);
}
}
このサンプルでは、昇順ソート、降順ソート、文字列の長さによるソート、辞書順ソート、複数条件を組み合わせたソート、nullを含むリストのソートといった、Javaのラムダ式とStreamのsortedでよく使う代表的なパターンをひと通り確認できます。コードを実際に実行してみることで、sortedメソッドとComparatorの動作イメージがより具体的に掴めるようになるはずです。
生徒:「sortedって単純に昇順に並び替えるだけのメソッドだと思っていましたが、Comparatorを使えばこんなにいろいろなソートができるんですね。」
先生:「そうですね。ラムダ式とComparatorを組み合わせると、Javaのリストや配列を自由自在に並び替えられるようになります。長さでソートしたり、複数条件を組み合わせたりと、実務でよく出てくるケースにも対応できますよ。」
生徒:「compareToを使った辞書順ソートもわかりやすかったです。文字列をアルファベット順に並べたいときには、まずcompareToを思い出せばよさそうですね。」
先生:「その通りです。文字列の自然な並び替えをしたいときは、compareToかComparator.naturalOrderを使えば基本的なソートはほとんど書けます。」
生徒:「複数条件ソートのサンプルもとても参考になりました。長さで比べてから、同じ長さのときだけ辞書順にするという書き方は、実際のデータでもよく使えそうです。」
先生:「複数条件を扱うときは、Comparator.comparingやthenComparingを使うと見通しのよいコードになります。慣れてくると、何段階の条件でも自然な流れで書けるようになりますよ。」
生徒:「nullを含むときにNullPointerExceptionが出ることがあったので、nullsFirstやnullsLastの存在を知れたのも大きな収穫でした。これなら例外を避けながらソートできますね。」
先生:「例外を防ぎつつ行儀の良いソートをするためには、とても役立つ仕組みです。画面表示用のリストなど、実践的な場面でぜひ活用してみてください。」
生徒:「今日の内容を自分のプロジェクトでも試して、ラムダ式とsortedを自然に使いこなせるようになりたいです。」
先生:「ぜひたくさん手を動かしてみてください。ソート処理を自由に書けるようになると、Javaで扱えるデータ表現の幅がぐっと広がりますよ。」