Collections.sort の役割をざっくりつかむ
Collections.sort は、
「List の中身を並び替えるための標準メソッド」
です。
配列には Arrays.sort がありましたよね。
その「List 版」が Collections.sort だと思ってください。
やってくれることはシンプルで、
List の中身を、その場で並び替える(破壊的ソート)
です。
Collections.sort(list); と呼ぶと、list の中身そのものが並び替えられ、
新しい List が返ってくるわけではありません。
一番基本:List<Integer> / List<String> を昇順にソートする
整数の List を昇順にソート
まずは一番シンプルな例から。
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class SortIntBasic {
public static void main(String[] args) {
List<Integer> numbers = new ArrayList<>();
numbers.add(30);
numbers.add(10);
numbers.add(20);
System.out.println("ソート前: " + numbers); // [30, 10, 20]
Collections.sort(numbers); // 昇順に並び替え
System.out.println("ソート後: " + numbers); // [10, 20, 30]
}
}
JavaInteger は「自然な順序」として「小さい順」が決まっているので、Collections.sort(numbers); と書くだけで、昇順に並びます。
ここで重要なのは、
戻り値を受け取っていない
numbers 自体の中身が書き換えられている
という点です。
文字列の List を辞書順にソート
String も自然な順序(辞書順)を持っています。
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class SortStringBasic {
public static void main(String[] args) {
List<String> names = new ArrayList<>();
names.add("Bob");
names.add("Alice");
names.add("Carol");
Collections.sort(names);
System.out.println(names); // [Alice, Bob, Carol]
}
}
Java英字の場合は A → Z の順(辞書順)になります。
日本語も、String の compareTo のルールに従って一応ソートされますが、
本格的な「五十音順」などをやろうとすると Collator など他の仕組みが必要になってきます。
Collections.sort が使える条件:要素が Comparable であること
T extends Comparable<? super T> って何を言っているのか
Collections.sort(List<T> list) のシグネチャ(定義)は、ざっくりこうなっています。
public static <T extends Comparable<? super T>> void sort(List<T> list)
Javaこの「T extends Comparable<? super T>」が少し難しく見えますが、
要するに
「list に入っている要素 T は、Comparable(compareTo で比較可能)でなければならない」
と言っているだけです。
Integer, String, LocalDate など、多くの標準クラスは Comparable を実装しているので、そのまま Collections.sort にかけられます。
自作クラスを sort しようとして怒られるパターン
自分で作ったクラスを List に入れてそのままソートすると、コンパイルエラーになります。
class User {
String name;
int age;
User(String name, int age) {
this.name = name;
this.age = age;
}
}
JavaList<User> users = new ArrayList<>();
users.add(new User("Alice", 30));
users.add(new User("Bob", 20));
Collections.sort(users); // コンパイルエラー:User は Comparable じゃない
JavaUser が Comparable<User> を実装していないので、
「どういう順番で並べていいか分からない」と怒られているわけです。
このときの選択肢は 2 つです。
クラスに自然な順序(標準の並び)を Comparable で埋め込む
ソート時に Comparator を渡して、「この場面の並べ方」を教える
この 2 本柱が、Collections.sort を理解するうえでのカギになります。
パターン1:Comparable を実装して自然な順序で sort する
User を「年齢昇順」で並べる自然順序にする
Comparable<User> を実装してみます。
class User implements Comparable<User> {
String name;
int age;
User(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public int compareTo(User other) {
return Integer.compare(this.age, other.age); // 年齢昇順
}
@Override
public String toString() {
return name + "(" + age + ")";
}
}
Javaこれで、Collections.sort(users) がそのまま動くようになります。
import java.util.*;
public class SortUserComparable {
public static void main(String[] args) {
List<User> users = new ArrayList<>();
users.add(new User("Alice", 30));
users.add(new User("Bob", 20));
users.add(new User("Carol", 25));
Collections.sort(users); // User.compareTo が使われる
System.out.println(users); // [Bob(20), Carol(25), Alice(30)]
}
}
JavaCollections.sort 側から見ると、
「要素が Comparable なら、その compareTo に従って並べればいい」
だけです。
Comparable を実装することで、
「User の標準の並び順=年齢昇順」という“自然順序”が決まりました。
パターン2:Comparator を渡して「場面ごとの並べ方」を指定する
自然順序とは違う並べ方をしたい場合
例えば、さっきの User の自然順序は「年齢昇順」になりましたが、ある場面では「名前の辞書順」に並べたいかもしれません。
その場合は、Collections.sort(List<T> list, Comparator<? super T> c) を使います。
import java.util.*;
public class SortUserComparator {
public static void main(String[] args) {
List<User> users = new ArrayList<>();
users.add(new User("Alice", 30));
users.add(new User("Bob", 20));
users.add(new User("Carol", 25));
Comparator<User> byName = new Comparator<User>() {
@Override
public int compare(User u1, User u2) {
return u1.name.compareTo(u2.name);
}
};
Collections.sort(users, byName);
System.out.println(users); // [Alice(30), Bob(20), Carol(25)]
}
}
JavaCollections.sort の第 2 引数に「並べ方のルール(Comparator)」を渡すことで、
自然順序とは別のソートを実現できます。
Java 8 以降の書き方:Comparator.comparing
Java 8 以降はラムダ式と Comparator.comparing を使うと、さらに読みやすくなります。
Collections.sort(
users,
Comparator.comparing(u -> u.name)
);
Javaあるいは、List 側の sort メソッドを使っても同様です。
users.sort(Comparator.comparing(u -> u.name));
Java複合条件や降順も簡単に書けます。
年齢昇順 → 同じ年齢なら名前昇順:
users.sort(
Comparator.comparing((User u) -> u.age)
.thenComparing(u -> u.name)
);
Java年齢降順:
users.sort(
Comparator.comparing((User u) -> u.age)
.reversed()
);
JavaCollections.sort(list, comparator) と list.sort(comparator) は本質的には同じですが、
新しいコードでは list.sort(...) を直接使うことが増えています。
Arrays.sort との違いと使い分け
配列なら Arrays.sort、List なら Collections.sort / List.sort
配列用のソートは Arrays.sort、
List 用のソートは Collections.sort(+ List.sort)と覚えておくと整理しやすいです。
配列:
int[] a = {3, 1, 2};
Arrays.sort(a); // a が [1, 2, 3] になる
JavaList:
List<Integer> list = Arrays.asList(3, 1, 2);
Collections.sort(list); // list が [1, 2, 3] になる
Java内部のアルゴリズム(Dual-Pivot QuickSort、TimSort など)は違いますが、
初心者のうちは
配列 → Arrays.sort
List → Collections.sort または list.sort
という対応だけ覚えておけば十分です。
「破壊的ソート」であることの注意点
元の順番は戻せない(戻したければコピーする)
Collections.sort(list) は、渡した list をその場で書き換えます。
元の順序を残しておきたい場合は、先にコピーを作っておく必要があります。
List<Integer> original = new ArrayList<>();
original.add(30);
original.add(10);
original.add(20);
List<Integer> sorted = new ArrayList<>(original);
Collections.sort(sorted);
System.out.println("元: " + original); // [30, 10, 20]
System.out.println("ソート後: " + sorted); // [10, 20, 30]
Javanew ArrayList<>(original) で「中身をコピーした別の List」を作り、
それに対して sort をかける、というパターンはよく使います。
ソート対象の List は「変更可能」である必要がある
Collections.sort は List の要素を入れ替えるので、
要素入れ替えをサポートしていない List に対しては UnsupportedOperationException が起こることがあります。
例えば、
List<Integer> list = Arrays.asList(3, 1, 2);
Collections.sort(list); // これは OK(中身の要素の入れ替えは許される実装)
Javaこの例は動きますが、「読み取り専用ビュー」や特別な List 実装に対しては注意が必要です。
特に「Collections.unmodifiableList(...) でラップされた List」などは、
sort しようとすると例外になります。
「ソートしたい List は、本当に変更可能か?」は、頭の片隅で意識しておくとよいです。
まとめ:Collections.sort を自分の中でどう位置づけるか
Collections.sort を初心者向けに整理すると、こうなります。
- List の中身を、その場で並び替えるメソッド(破壊的ソート)。
Collections.sort(list)が使えるのは、「要素が Comparable(自然順序を持つ)」とき。- 自作クラスは、自然順序で並べたいなら
Comparableを実装する。 - 自然順序とは別の並びにしたいときは、
Collections.sort(list, comparator)でComparatorを渡す。 - 配列なら
Arrays.sort、List ならCollections.sort/list.sortを使い分ける。
