sorted を一言でいうと
Stream#sorted は、ストリームに流れてくる要素を「並べ替えた新しいストリーム」を返す中間操作です。
「順番を整える係」が sorted だと思ってください。
sorted の基本と「自然順序」
引数なし sorted の意味
sorted()(引数なし)は、要素の「自然順序(natural order)」で並べ替えます。
自然順序とは、Comparable を実装しているクラスが自分で定義している「標準の並び順」です。
例えば String なら辞書順、Integer なら数値の昇順が自然順序です。
import java.util.List;
public class SortedBasic {
public static void main(String[] args) {
List<String> names = List.of("Charlie", "Alice", "Bob");
List<String> sorted =
names.stream()
.sorted() // 自然順序(String の辞書順)
.toList();
System.out.println(sorted); // [Alice, Bob, Charlie]
}
}
Javaこのとき、元の names の順番は変わらず、新しいリストだけがソートされています。
Comparator を使った sorted の設計
引数あり sorted の基本形
「自然順序ではなく、自分で決めたルールで並べたい」ときは、Comparator を渡します。
<R> Stream<R> sorted(Comparator<? super R> comparator)
Java例えば、文字列を「長さの昇順」で並べたい場合はこう書きます。
import java.util.Comparator;
import java.util.List;
public class SortedByLength {
public static void main(String[] args) {
List<String> names = List.of("Bob", "Alice", "Charlie");
List<String> sortedByLength =
names.stream()
.sorted(Comparator.comparingInt(String::length))
.toList();
System.out.println(sortedByLength); // [Bob, Alice, Charlie]
}
}
JavaComparator.comparingInt(String::length) は「長さで比較する Comparator」を作るヘルパーです。
自作クラスと sorted
Comparable を実装して自然順序で並べる
自分のクラスを sorted()(引数なし)で並べたいなら、そのクラスに Comparable を実装して「標準の並び順」を決めておくのが王道です。
class User implements Comparable<User> {
private final String name;
private final int age;
User(String name, int age) {
this.name = name;
this.age = age;
}
String getName() { return name; }
int getAge() { return age; }
@Override
public int compareTo(User other) {
return this.name.compareTo(other.name); // 名前の辞書順
}
@Override
public String toString() {
return name + "(" + age + ")";
}
}
Javaこれで、次のように書けます。
import java.util.List;
public class SortedUserByName {
public static void main(String[] args) {
List<User> users = List.of(
new User("Charlie", 25),
new User("Alice", 20),
new User("Bob", 30)
);
List<User> sorted =
users.stream()
.sorted() // User の compareTo に従ってソート
.toList();
System.out.println(sorted); // [Alice(20), Bob(30), Charlie(25)]
}
}
JavacompareTo の中身を「年齢順」に変えれば、自然順序も年齢順になります。
Comparator で柔軟に並べ替える
「自然順序は名前順にしておきたいけど、たまに年齢順でも並べたい」といった場合は、Comparator を渡す sorted を使います。
import java.util.Comparator;
import java.util.List;
public class SortedUserByAge {
public static void main(String[] args) {
List<User> users = List.of(
new User("Charlie", 25),
new User("Alice", 20),
new User("Bob", 30)
);
List<User> sortedByAge =
users.stream()
.sorted(Comparator.comparingInt(User::getAge))
.toList();
System.out.println(sortedByAge); // [Alice(20), Charlie(25), Bob(30)]
}
}
JavaComparator.comparingInt(User::getAge) は「年齢で昇順に並べる Comparator」です。
さらに、「年齢昇順、同じ年齢なら名前順」のような複合条件も簡単に書けます。
Comparator<User> byAgeThenName =
Comparator.comparingInt(User::getAge)
.thenComparing(User::getName);
List<User> sorted =
users.stream()
.sorted(byAgeThenName)
.toList();
Javasorted の位置づけとパイプライン設計
filter / map / distinct / sorted の流れ
Stream の中での sorted の役割は、「最終的な順番を整えること」です。
よくある流れは、次のような順番です。
絞り込みは filter
形を変えるのは map
重複を消すのは distinct
順番を整えるのが sorted
例えば、「20 歳以上のユーザーの“重複しない名前”を“名前順”に並べる」ならこうなります。
List<String> names =
users.stream()
.filter(u -> u.getAge() >= 20) // 絞り込み
.map(User::getName) // 変換
.distinct() // 重複排除
.sorted() // 名前の自然順(辞書順)
.toList();
Java左から右に読むだけで、「何をしているか」が自然に追えるはずです。
sorted のコストと注意点
全体を並べ替える=それなりに重い
sorted は、内部的には「全要素を一度集めてからソート」します。
つまり、要素数が多いほど計算量もメモリ使用量も増えます。
通常のサイズのリストなら気にしなくて構いませんが、「とにかく重い処理を避けたい場面」では、
本当にソートが必要か、ソートする要素数を減らせないか(先に filter や limit を入れるなど)を意識しておくとよいです。
まとめ:sorted を自分の言葉で整理する
sorted をあなたの言葉でまとめるなら、
「ストリームの要素を、自然順序または指定した Comparator に従って並べ替えた新しいストリームを返す中間操作」
です。
特に意識しておきたいのは、
引数なしは Comparable による自然順序
引数ありは Comparator で自由にルールを決められる
filter / map / distinct のあとに置くと、パイプラインの意図が読みやすい
自作クラスでは、自然順序を使うなら Comparable、柔軟に並べたいなら Comparator を設計する
というあたりです。
