1. コレクションでの要素検索
標準メソッドによる検索
たとえば、名前のリストがあるとします。
List<String> names = List.of("アンナ", "ボリス", "ビクトリア", "アンナ", "ドミトリー");
Java には検索のための便利なメソッドがいくつかあります。
- contains(Object o) — コレクションにその要素が含まれているかを確認します。
- indexOf(Object o) — 最初に見つかった位置のインデックスを返します(見つからない場合は -1)。
- lastIndexOf(Object o) — 最後に見つかった位置のインデックスを返します(見つからない場合は -1)。
例:
System.out.println(names.contains("アンナ")); // true
System.out.println(names.indexOf("アンナ")); // 0
System.out.println(names.lastIndexOf("アンナ")); // 3
System.out.println(names.contains("セルゲイ")); // false
豆知識: Set のようなコレクションには indexOf と lastIndexOf はありません — Set にはそもそもインデックスがなく、一意な値だけが保持されます。
条件による検索
特定の値ではなく、条件に合う要素を見つけたいことがあります。たとえば、6 文字より長い最初の名前を見つける、といったケースです。通常の for ループで十分で、条件に合うものが見つかったら — break を使います。
List<String> names = List.of("アンナ", "ボリス", "ビクトリア", "アンナ", "ドミトリー");
String found = null;
for (String name : names) {
if (name.length() > 6) {
found = name;
break; // 最初に条件を満たす要素を見つけたので、ループを抜ける
}
}
System.out.println(found); // ビクトリア
最大値と最小値の検索
要素が相互に比較可能(たとえば数値)なコレクションなら、クラス Collections を使って最大値・最小値をすばやく見つけられます。
List<Integer> numbers = List.of(10, 5, 20, 7, 20, 3);
int max = Collections.max(numbers); // 20
int min = Collections.min(numbers); // 3
System.out.println("最大値: " + max);
System.out.println("最小値: " + min);
重要: 要素は比較可能(Comparable を実装)である必要があります。そうでない場合はコンパレータを渡してください。
2. コレクションのソート
リストのデフォルトのソート
ソートできるのは可変のリスト(例: ArrayList、LinkedList)のみです。Set や Map のようなコレクションは直接のソートをサポートしていません。
デフォルトでは「自然順序」に従って並び替えます。数値なら昇順、文字列なら辞書順です。
List<Integer> numbers = new ArrayList<>(List.of(5, 1, 7, 3));
Collections.sort(numbers);
System.out.println(numbers); // [1, 3, 5, 7]
同じことをリストのメソッド sort でも行えます:
List<Integer> numbers = new ArrayList<>(List.of(5, 1, 7, 3));
numbers.sort(null); // null は自然順序を使うという意味
System.out.println(numbers); // [1, 3, 5, 7]
Comparator を使ったソート
独自の規則が必要な場合、たとえば文字列の長さでソートするには次のようにします。
List<String> words = new ArrayList<>(List.of("kot", "slon", "mukha", "nosorog"));
words.sort(Comparator.comparingInt(String::length));
System.out.println(words); // [kot, slon, mukha, nosorog]
逆順:
words.sort(Comparator.comparingInt(String::length).reversed());
System.out.println(words); // [nosorog, mukha, slon, kot]
古いスタイル( Collections.sort 経由):
Collections.sort(words, Comparator.comparingInt(String::length));
3. コレクションごとのソートの注意点
ソートで変更できるのはリストだけ
ソート用メソッド(sort、Collections.sort)は、要素順序を持つコレクション(例: List)でのみ動作します。Set と Map にはそのようなメソッドは用意されていません。
Set をソートしようとすると:
Set<Integer> mySet = new HashSet<>(List.of(3, 1, 2));
Collections.sort(mySet); // コンパイルエラー: sort は List を期待します!
もし Set から並び替え済みのリストが欲しい場合:
List<Integer> sortedFromSet = new ArrayList<>(mySet);
Collections.sort(sortedFromSet);
System.out.println(sortedFromSet); // [1, 2, 3]
Map のソート: キーまたは値で並べ替える
Map 自体を直接ソートすることはできませんが、次のようにすれば可能です。
- キーと値のペア(エントリ)のリストを取得する
- 必要な規則でそのリストをソートする
- 必要に応じて新しい Map に組み立て直す
例: 値でソート
Map<String, Integer> scores = Map.of(
"アンナ", 15,
"ボリス", 20,
"ヴィカ", 12
);
List<Map.Entry<String, Integer>> entries = new ArrayList<>(scores.entrySet());
entries.sort(Map.Entry.comparingByValue());
for (Map.Entry<String, Integer> entry : entries) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
// ヴィカ: 12
// アンナ: 15
// ボリス: 20
オブジェクトをフィールドでソートする
たとえば、次のようなユーザークラスがあるとします。
class User {
String name;
int age;
User(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return name + " (" + age + ")";
}
}
そしてユーザーのリスト:
List<User> users = new ArrayList<>(List.of(
new User("アンナ", 22),
new User("ボリス", 18),
new User("ヴィカ", 25)
));
年齢でソート:
users.sort(Comparator.comparingInt(u -> u.age));
System.out.println(users); // [ボリス (18), アンナ (22), ヴィカ (25)]
逆順:
users.sort(Comparator.comparingInt((User u) -> u.age).reversed());
System.out.println(users); // [ヴィカ (25), アンナ (22), ボリス (18)]
4. 検索とソートでよくあるミス
誤りその1: 不変リストをソートしようとする。 List.of(...) で作られたリストは変更できません — sort を呼ぶと UnsupportedOperationException が送出されます。
List<Integer> immutable = List.of(3, 1, 2);
immutable.sort(null); // 例外がスローされる!
誤りその2: Set や Map を直接ソートする。 ソート用メソッドは Set と Map では動作しません。並べ替えたい場合は、まずデータをリストに変換してください。
誤りその3: オブジェクトの比較方法が不適切。 比較のために整数をそのまま減算してはいけません — オーバーフローの可能性があります。u1.age - u2.age の代わりに Integer.compare か Comparator.comparingInt を使用しましょう。
// users.sort((u1, u2) -> u1.age - u2.age); // 動くには動くが、オーバーフローの危険あり!
誤りその4: 複雑な検索に contains を使う。 メソッド contains は完全一致(equals)だけを判定します。部分文字列やオブジェクトの特定フィールドで探したい場合は、条件チェック付きのループや Comparator/Stream を使ってください。
GO TO FULL VERSION