Collections クラスの便利メソッド
Collections クラスの便利メソッド とは
java.util.Collections の sort / max / min / reverse / shuffle を使いこなして、List を自由自在に操作しよう。
Collections クラスは「リスト用の万能ナイフ」
java.util.Collections は、List Set Map といった コレクション を裏から支える静的ユーティリティクラスです。並び替え、最大値・最小値の検索、反転、シャッフル、出現回数のカウントまで、自分で書こうとすると地味に面倒な処理がワンライナーで片付きます。
Collections(s 付き) とCollection(s なし) は 完全に別物 です。CollectionはListやSetの親インターフェース、Collectionsは便利メソッドの詰め合わせた ユーティリティクラス です。名前が一文字違いで初心者を混乱させる Java あるあるなので、最初にしっかり覚えてしまいましょう。
このレッスンでは、int[] の配列を受け取って List<Integer> に変換し、Collections.sort で昇順に並べてから Collections.max で最大値を返す sortAndMax メソッドを実装しながら、Collections の使い方を体に染み込ませていきます。空配列のときは -1 を返す約束です。
よく使う Collections のメソッド
まずは Collections の代表的なメソッドを一覧で押さえておきましょう。下の表は実務でも頻出のメソッドだけを厳選したものです。
Collections.sort(list)—listを 昇順 にその場で並べ替える (破壊的)Collections.max(list)—listの中の 最大値 を返すCollections.min(list)—listの中の 最小値 を返すCollections.reverse(list)—listの要素順を その場で反転 するCollections.shuffle(list)—listの要素を ランダムに並べ替えるCollections.frequency(list, target)—listの中にtargetが 何回出てくるか を数える
気をつけたいのは、sort reverse shuffle は 元の List を直接書き換える という点です。「並べ替えた新しい List が返ってくる」と勘違いして List<Integer> sorted = Collections.sort(list); のように書くとコンパイルエラーになります。sort の戻り値は void だからです。
Collections.sortはO(n log n)のTimsortという安定ソートで実装されています。要素数が100 万でも 1 秒もかからずに片付くので、よほど特殊な事情がない限り自前で書く必要はありません。「車輪の再発明」を避けるのも、立派なエンジニアスキルです。
int[] を List に変換する 3 つの道
Collections のメソッドは int[] には直接かけられません。Collections.sort(int[]) のような呼び出しはコンパイルエラーになります。理由は Collections のメソッドが List<E> を引数に取るからで、int のような プリミティブ型の配列 は List<int> にはできない (List<Integer> ならできる) からです。
そのため、まず int[] を List<Integer> に変換する必要があります。代表的なやり方は次のとおりです。
Java
int[] arr = {3, 1, 4, 1, 5};
// 1. for ループで詰める (確実)
List<Integer> list1 = new ArrayList<>();
for (int v : arr) {
list1.add(v);
}
// 2. Arrays.stream で変換 (Java 8 以降)
List<Integer> list2 = Arrays.stream(arr)
.boxed()
.collect(Collectors.toList());
// 3. Integer[] なら Arrays.asList が使える (要 boxing)
Integer[] boxed = {3, 1, 4, 1, 5};
List<Integer> list3 = new ArrayList<>(Arrays.asList(boxed));Arrays.asList には大きな罠があり、これだけで本が 1 章書けるレベルです (詳しくは後の「よくある間違い」で扱います)。今回のレッスンでは、いちばん素直で誤解の少ない for-each + ArrayList.add を使います。
動きを図で追ってみる
それでは sortAndMax([3, 1, 4, 1, 5]) を実行したときに、内部で何が起きているかをフロー図で追ってみましょう。int[] から List<Integer> への変換、Collections.sort での並び替え、Collections.max での最大値取得、という 3 ステップで進みます。
この図のポイントは、Collections.sort を呼んだあとに list の中身そのものが書き換わっている点です。sort の戻り値を新しい変数で受け取っているわけではない、というところを必ず押さえてください。
実装してみる
それでは Solution.sortAndMax(int[] arr) の実装例を見てみましょう。
Java
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Solution {
public static int sortAndMax(int[] arr) {
if (arr.length == 0) {
return -1;
}
List<Integer> list = new ArrayList<>();
for (int v : arr) {
list.add(v);
}
Collections.sort(list);
return Collections.max(list);
}
}読み下すと「空配列なら -1 を返す。そうでなければ int[] を List<Integer> に詰め替え、Collections.sort で昇順に並べ、Collections.max で最大値を取って返す」となります。シンプルですが、Collections の典型的な使い方が 1 メソッドに凝縮されています。
「
sortしてからmaxを取るなら、sort後のlist.get(list.size() - 1)でも最大値が取れるのでは?」と気づいた人は鋭いです。実際そのとおりで、Collections.maxを呼ばなくても末尾参照で済みます。今回はあえてCollections.maxを使う練習として書きますが、両方の手段を知っておくと現場で柔軟に書けます。
よくある間違い
Collections 関連で初心者がハマりやすい代表的な罠は 3 つあります。
Arrays.asListで返るリストは固定長 —Arrays.asList(1, 2, 3)の戻り値はaddやremoveを呼ぶとUnsupportedOperationExceptionが飛びます。サイズを変えたいならnew ArrayList<>(Arrays.asList(...))のようにArrayListで ラップ してくださいArrays.asList(int[])は要素 1 個のリストになる —int配列をArrays.asList(arr)に渡すと、List<int[]>(要素数1の、配列を 1 個だけ持つリスト) になってしまいます。Collections.sortも期待どおりに動きません。プリミティブ配列を List 化したいときはforループかArrays.stream(arr).boxed()を使う必要がありますCollections.sortをComparatorなしで呼ぶ条件 —Collections.sort(list)が引数 1 つで動くのは、要素がComparableを実装している型 (IntegerStringDoubleなど) のときだけです。自作クラスのリストをsortしたい場合は、クラスにimplements Comparable<MyClass>を書くか、Collections.sort(list, comparator)でComparatorを渡す必要があります
もうひとつ、Collections.max を 空のリスト に対して呼ぶと NoSuchElementException が飛びます。今回の課題では空配列の段階で -1 を返してガードしているので問題ありませんが、本番コードでは必ず list.isEmpty() チェックを入れる癖をつけてください。
エラーメッセージの読み方は
Java学習の生命線です。UnsupportedOperationExceptionを見たら「固定長のコレクションを変更しようとした」と読み替えましょう。Arrays.asList、List.of、Collections.unmodifiableListなどはすべて 書き換え禁止 のリストを返します。
やってみよう
それでは右側のエディタで Solution.sortAndMax(int[] arr) を完成させてみましょう。
- メソッドの先頭で
if (arr.length == 0) return -1;の空配列ガードを書く List<Integer> list = new ArrayList<>();で空のリストを用意するfor (int v : arr) list.add(v);で配列の要素を順番に詰めるCollections.sort(list);で昇順に並べ替えるreturn Collections.max(list);で最大値を返す
テストが緑になったら、Collections.min(list) に書き換えて最小値を返してみたり、Collections.reverse(list) を挟んで降順にしたあとに list.get(0) で最大値を取ったり、いろいろな書き方を試してみてください。Collections のメソッドは互いに組み合わせやすく設計されているので、sort + reverse で降順ソートが書ける、というような メソッドを部品として組む 感覚が身についてきます。
さらに余力があれば、Collections.frequency(list, 1) を呼んで list の中に 1 が何回出てくるか数えてみたり、Collections.shuffle(list) を呼んでから list の中身を System.out.println で観察してみると、Collections の世界がぐっと身近になります。今後 Java で List を触るたびに、ここで覚えたメソッドが助けてくれるはずです。
よくある質問
Q. 中級の内容は実務でどれくらい使いますか?
A. Collection(List/Map/Set)、Stream、例外処理、ジェネリクスは毎日のように登場します。Date/Time API、Files、try-with-resources も実務で頻出するため、本コースの内容は実プロジェクトでそのまま役立ちます。
Q. Stream と for ループはどっちで書くべき?
A. 可読性で選んでください。filter + map + collect が綺麗にハマるなら Stream、副作用や複雑な分岐が多いなら for ループの方が読みやすいです。一律にどちらを使うべきという正解はなく、チームのコーディング規約に合わせるのが現実的です。
Q. 次のステップでは何を学ぶべきですか?
A. 中級の基礎が固まったら、Spring Boot で Web API を作る、JUnit でテストを書く、Maven/Gradle でビルドを管理する、といった実プロジェクトのスキルに進むと効果的です。OSS のコードを読む経験も大きく成長を促します。
次のレッスン
次は コレクション基礎 まとめクイズ で、コレクション基礎 まとめクイズ を学びます。
事前確認 — 進む前に次の 3 つができることを確認しましょう。
- Collections の要点を自分の言葉で説明できる
- このレッスンの最小コード (または操作手順) を見ずに書ける
- 練習問題やクイズで間違えた箇所を読み直して理解した
理解度チェック (30 秒)
Q. Collections とは何か、1 文で説明してください。
A. 本文の「このレッスンで分かること」または冒頭の説明文を見直し、自分の言葉で要約できれば OK。詰まったら本レッスンの最初の H2 セクションを読み返してみましょう。
関連レッスン
要件
- クラス名は
Solution、メソッド名はsortAndMax、引数はint[] arrひとつにすること - 戻り値の型は
intで、int[]をList<Integer>に変換してからCollections.sortとCollections.maxを使って最大値を返すこと - 配列が空 (
arr.length == 0) のときは-1を返すこと (Collections.maxを空リストに呼ぶと例外になるため必ずガードする)
入出力例
test-cases.txt
sortAndMax([3,1,4,1,5]) → 5
sortAndMax([100]) → 100
sortAndMax([]) → -1
sortAndMax([-5,-10,-1]) → -1
sortAndMax([7,7,7,7]) → 7
sortAndMax([1,2,3,4,5]) → 5