タイトル: ループ処理
SEOタイトル: Java ループ処理完全ガイド(for / while / 拡張 for / Stream)
| この記事の要点 |
|
4 種のループ構文
// 1. 古典 for: 初期化 / 条件 / 更新
for (int i = 0; i < 10; i++) {
System.out.println(i);
}
// 2. while: 条件チェック → 実行
int i = 0;
while (i < 10) {
System.out.println(i);
i++;
}
// 3. do-while: 実行 → 条件チェック(最低 1 回実行)
int j = 0;
do {
System.out.println(j);
j++;
} while (j < 10);
// 4. 拡張 for (for-each): Collection / 配列
List names = List.of("taro", "jiro", "saburo");
for (String name : names) {
System.out.println(name);
}
int[] nums = {1, 2, 3};
for (int n : nums) {
System.out.println(n);
}
break と continue
for (int i = 0; i < 10; i++) {
if (i == 3) continue; // 3 だけスキップ
if (i == 7) break; // 7 で脱出
System.out.println(i);
}
// 0, 1, 2, 4, 5, 6
// 無限ループ + break
while (true) {
String input = scanner.nextLine();
if (input.equals("quit")) break;
process(input);
}
ラベル付き break / continue(多重ループ脱出)
outer:
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
if (matrix[i][j] == TARGET) {
System.out.println("Found at " + i + "," + j);
break outer; // ★ 外側ループも抜ける
}
}
}
// continue にも使える
outer:
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
if (skip(i, j)) continue outer; // 外側の次の i へ
process(i, j);
}
}
Stream API による関数型ループ
import java.util.stream.*;
import java.util.List;
List nums = List.of(1, 2, 3, 4, 5);
// forEach: 拡張 for 相当
nums.stream().forEach(System.out::println);
nums.forEach(System.out::println); // Collection 直接 forEach も可
// filter + map + collect
List doubled = nums.stream()
.filter(n -> n % 2 == 0) // 偶数のみ
.map(n -> n * 2) // 2 倍
.collect(Collectors.toList());
// [4, 8]
// IntStream.range: インデックスベースループ
IntStream.range(0, 10).forEach(i -> System.out.println(i));
// 0, 1, 2, ..., 9
IntStream.rangeClosed(1, 10).sum(); // 1+2+...+10 = 55
// 並列実行(CPU 集約処理向け)
nums.parallelStream()
.map(this::heavyCompute)
.forEach(System.out::println);
Iterator による明示的ループ
List list = new ArrayList<>(List.of("a", "b", "c"));
Iterator it = list.iterator();
while (it.hasNext()) {
String s = it.next();
if (s.equals("b")) {
it.remove(); // ★ ループ中の安全な削除
}
}
System.out.println(list); // [a, c]
ConcurrentModificationException 回避
拡張 for ループ中に Collection を変更すると、次のイテレーションで例外が出ます。
List list = new ArrayList<>(List.of("a", "b", "c"));
// ❌ ConcurrentModificationException
for (String s : list) {
if (s.equals("b")) {
list.remove(s);
}
}
// ✅ 方法 A: Iterator.remove()
Iterator it = list.iterator();
while (it.hasNext()) {
if (it.next().equals("b")) it.remove();
}
// ✅ 方法 B: removeIf() (Java 8+)
list.removeIf(s -> s.equals("b"));
// ✅ 方法 C: Stream で新しいリスト生成
list = list.stream()
.filter(s -> !s.equals("b"))
.collect(Collectors.toList());
性能比較: for vs 拡張 for vs Stream
| 方法 | 速度 | 可読性 | 用途 |
|---|---|---|---|
| 古典 for(インデックス) | 最速(プリミティブ配列) | 低 | 性能クリティカル / インデックス必要 |
| 拡張 for | 高速 | 高 | ★ 通常はこれ |
| Stream.forEach | やや遅い(オートボックシング) | 中 | 関数型 / パイプライン |
| parallelStream | 大量データで速い | 中 | CPU 集約 / 副作用なし |
| Iterator | 拡張 for と同等 | 低 | 削除を伴うループ |
無限ループの書き方
// while(true)
while (true) {
if (shouldStop()) break;
process();
}
// for(;;)
for (;;) {
if (shouldStop()) break;
process();
}
// do-while(true)
do {
process();
} while (!shouldStop());
Map のループ
Map ages = Map.of("taro", 30, "jiro", 25);
// entrySet: キーと値両方
for (Map.Entry e : ages.entrySet()) {
System.out.println(e.getKey() + ": " + e.getValue());
}
// keySet / values
for (String k : ages.keySet()) { ... }
for (Integer v : ages.values()) { ... }
// forEach (Java 8+)
ages.forEach((k, v) -> System.out.println(k + ": " + v));
FAQ
Q: 拡張 for でインデックスが欲しい
A: 拡張 for では取れません。古典 for を使うか、IntStream.range(0, list.size()).forEach(i -> ...)。
Q: Stream.forEach と List.forEach、どちらが速い?
A: ほぼ同じ。Stream は遅延評価が効くパイプライン全体で考えるべきで、単独 forEach は List.forEach や拡張 for を推奨。
Q: parallelStream は常に速い?
A: いいえ。スレッド管理オーバーヘッドがあるため、要素数が少ない / 処理が軽いと逆に遅くなります。