for 文の全体像
for 文は「繰り返し」を最もコンパクトに書ける基本構文です。回数を決めて処理する、配列やリストを順番に処理する、といった場面で頻出します。伝統的な for (初期化; 条件; 更新) と、要素を直接取り出す拡張 for-each の2種類を使い分けます。重要なのは「どこから始め、どこで終わり、どう進むか」を明確に設計することです。
基本形と3つの要素
最小の書式と動き
for (int i = 0; i < 5; i++) {
System.out.println(i); // 0,1,2,3,4
}
Java- 初期化: 最初に一度だけ実行(
int i = 0) - 条件: 周回の頭でチェック。
trueなら本体を実行、falseで終了(i < 5) - 更新: 周回の最後に実行(
i++)
「開始値」「終了条件」「増減のステップ」を一行に集約できるため、意図が読みやすいのが利点です。
例題: 合計と平均(整数→小数)
public class SumAvg {
public static void main(String[] args) {
int[] nums = {3, 8, 2, 7};
int sum = 0;
for (int i = 0; i < nums.length; i++) {
sum += nums[i];
}
double avg = sum / (double) nums.length;
System.out.printf("sum=%d avg=%.2f%n", sum, avg);
}
}
Java「添字でアクセスする」典型パターンです。小数平均は片方を double にして切り捨てを回避します。
重要ポイントの深掘り:境界とオフバイワン
0 始まりの配列と終了条件
Java の配列や List は 0 始まりです。最後の要素の添字は length - 1。終了条件は「未満(<)」が定番で、境界を外しにくい書き方です。
int[] a = {10, 20, 30};
for (int i = 0; i < a.length; i++) {
System.out.println(a[i]);
}
Java「<= を使ってしまい最後で範囲外アクセス」になりやすいので、< を習慣化しましょう。
逆順走査の安全パターン
String[] words = {"Java", "is", "fun"};
for (int i = words.length - 1; i >= 0; i--) {
System.out.println(words[i]);
}
Java開始は「最後の添字」、終了条件は「i >= 0」。この形が最も読みやすく安全です。
重要ポイントの深掘り:更新式と continue/break の挙動
更新は「本体の最後」に実行される
for の更新式は、周回の最後に必ず実行されます。continue に到達しても「更新して次周」へ進むため、while より無限ループを起こしにくいのが利点です。
for (int i = 0; i < 5; i++) {
if (i == 2) continue; // この周の残りをスキップ、でも i++ は実行される
System.out.println(i);
}
Java終了したいときは break でループを抜けます。どの範囲を止めたいか(周回だけ/ループ全体/メソッド全体)で continue/break/return を使い分けます。
拡張 for 文(for-each)
要素を直接取り出す簡潔な反復
配列や Iterable(List など)の全要素を処理するだけなら、拡張 for が読みやすいです。添字の管理が不要になり、境界バグを避けられます。
List<String> names = java.util.List.of("sato", "suzuki", "sakai");
for (String n : names) {
System.out.println(n);
}
Java拡張 for は「今どの位置か」「次の添字へ進む」といった制御ができません。インデックスが必要、要素の一部だけ処理、逆順で処理などの場合は通常の for を使います。
配列・リストの応用パターン
条件付きで集計(フィルタ+累積)
int[] values = {3, -1, 8, -5, 2};
int sum = 0;
for (int v : values) {
if (v < 0) continue; // 不正値はスキップ
sum += v;
}
System.out.println(sum); // 13
Javaガードで対象外を早めに弾き、主処理をフラットに保つと読みやすくなります。
添字を使って「先頭/末尾」を意識する
int[] a = {10, 20, 30, 40};
for (int i = 0; i < a.length; i++) {
boolean first = (i == 0);
boolean last = (i == a.length - 1);
System.out.printf("%d%s%n", a[i], last ? "" : ", ");
}
Java「区切り文字の扱い」など、位置に応じた分岐が必要なら添字付きの for が便利です。
ネストとラベル、早期終了の設計
二重ループの「見つかったら外へ」
int target = 42;
int[][] grid = {{1, 2, 3}, {10, 42, 7}, {8, 9, 10}};
found:
for (int r = 0; r < grid.length; r++) {
for (int c = 0; c < grid[r].length; c++) {
if (grid[r][c] == target) {
System.out.printf("found at (%d,%d)%n", r, c);
break found; // 外側まで一気に抜ける
}
}
}
Javaラベル付き break は「どのループを抜けたいか」を明確にでき、フラグ変数より読みやすいです。ラベル名は意図が伝わる短い単語にしましょう。
よくある落とし穴と対策
オフバイワン(+1/-1)の境界ミス
<= を使って最後の添字を踏む、逆順の開始位置を間違える、といったミスは定番です。書いたら「0、最後、空配列」の3ケースで動作確認する癖をつけましょう。
同じ式で複数の増減
int i = 0;
// 読みにくい例:避ける
int r = i++ + ++i;
Java増減記号を式に混ぜると可読性が急落します。ステップに分解して書くのが安全です。
更新・終了条件の一貫性
「増やすなら未満(i < limit)」「減らすなら 0 以上(i >= 0)」をセットで覚えると、設計が安定します。
実用例で身につける
例 1: 文字列のトークン化(添字で制御)
public class Tokenize {
public static void main(String[] args) {
String s = "A,B,C";
String[] parts = s.split(",");
for (int i = 0; i < parts.length; i++) {
System.out.printf("[%d]=%s%n", i, parts[i]);
}
}
}
Java例 2: 2 次元配列の整形出力
public class MatrixPrint {
public static void main(String[] args) {
int[][] m = {{1,2,3},{4,5,6}};
for (int r = 0; r < m.length; r++) {
for (int c = 0; c < m[r].length; c++) {
System.out.printf("%3d", m[r][c]);
}
System.out.println();
}
}
}
Java例 3: for-each で読みやすく
public class ForEachDemo {
public static void main(String[] args) {
java.util.List<String> list = java.util.List.of("Java", "is", "fun");
for (String w : list) {
System.out.println(w);
}
}
}
Java設計の指針(重要ポイントのまとめ)
- 開始値・終了条件・更新の関係を一貫させる。「増やす×未満」「減らす×0以上」を基本形に。
- 境界は
<を優先してオフバイワンを防ぐ。逆順は「length-1 から 0 まで」。 - 対象外は
continueで早めに弾き、主処理をフラットに保つ。終了はbreak、メソッド終了はreturn。 - インデックス不要の全件処理は拡張
for。位置や逆順が必要なら通常のfor。 - 二重ループの早期終了はラベル付き
breakが最短で明快。
