Collections クラスの便利メソッド

生田 陸人
LuaGate エンジニア / 現役エンジニア
編集 LuaGate編集部

Collections クラスの便利メソッド とは

java.util.Collections の sort / max / min / reverse / shuffle を使いこなして、List を自由自在に操作しよう。

Collections クラスは「リスト用の万能ナイフ」

java.util.Collections は、List Set Map といった コレクション を裏から支える静的ユーティリティクラスです。並び替え、最大値・最小値の検索、反転、シャッフル、出現回数のカウントまで、自分で書こうとすると地味に面倒な処理がワンライナーで片付きます。

Collections (s 付き) と Collection (s なし) は 完全に別物 です。CollectionListSet の親インターフェース、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.sortO(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 ステップで進みます。

diagram (will load when visible)

この図のポイントは、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) の戻り値は addremove を呼ぶと 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.sortComparator なしで呼ぶ条件Collections.sort(list) が引数 1 つで動くのは、要素が Comparable を実装している型 (Integer String Double など) のときだけです。自作クラスのリストを sort したい場合は、クラスに implements Comparable<MyClass> を書くか、Collections.sort(list, comparator)Comparator を渡す必要があります

もうひとつ、Collections.max空のリスト に対して呼ぶと NoSuchElementException が飛びます。今回の課題では空配列の段階で -1 を返してガードしているので問題ありませんが、本番コードでは必ず list.isEmpty() チェックを入れる癖をつけてください。

エラーメッセージの読み方は Java 学習の生命線です。UnsupportedOperationException を見たら「固定長のコレクションを変更しようとした」と読み替えましょう。Arrays.asListList.ofCollections.unmodifiableList などはすべて 書き換え禁止 のリストを返します。

やってみよう

それでは右側のエディタで Solution.sortAndMax(int[] arr) を完成させてみましょう。

  1. メソッドの先頭で if (arr.length == 0) return -1; の空配列ガードを書く
  2. List<Integer> list = new ArrayList<>(); で空のリストを用意する
  3. for (int v : arr) list.add(v); で配列の要素を順番に詰める
  4. Collections.sort(list); で昇順に並べ替える
  5. 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 の世界がぐっと身近になります。今後 JavaList を触るたびに、ここで覚えたメソッドが助けてくれるはずです。

よくある質問

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 つができることを確認しましょう。

  1. Collections の要点を自分の言葉で説明できる
  2. このレッスンの最小コード (または操作手順) を見ずに書ける
  3. 練習問題やクイズで間違えた箇所を読み直して理解した

理解度チェック (30 秒)

Q. Collections とは何か、1 文で説明してください。

この章のポイント

A. 本文の「このレッスンで分かること」または冒頭の説明文を見直し、自分の言葉で要約できれば OK。詰まったら本レッスンの最初の H2 セクションを読み返してみましょう。

関連レッスン

要件

  1. クラス名は Solution、メソッド名は sortAndMax、引数は int[] arr ひとつにすること
  2. 戻り値の型は int で、int[]List<Integer> に変換してから Collections.sortCollections.max を使って最大値を返すこと
  3. 配列が空 (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

ヒント

main.java
main.java
学習モード

メモ

Collections クラスの便利メソッド

⌘S で保存