ここでは、拡張 for 文(for-each)を実務で「安全・堅牢」に使うベストプラクティス集を、
実際の業務コードの形で紹介します。
目的は、
「きれいに動く」だけでなく「安全で保守しやすいコード」を書くこと。
(安全設計・例外処理・ロギング対応)
ベストプラクティス①
✅ null安全:コレクションが null のときに安全にスキップする
import java.util.List;
import java.util.Objects;
public class SafeLoopExample {
public static void main(String[] args) {
List<String> items = null;
// nullチェックを入れる
if (Objects.nonNull(items)) {
for (String item : items) {
System.out.println(item);
}
} else {
System.out.println("⚠️ items が null のため処理をスキップしました");
}
}
}
Java🧠 ポイント
- 実務では「DB結果」「APIレスポンス」が
nullのことがある。 for-eachにnullを渡すとNullPointerException。Objects.nonNull()/Objects.isNull()で防ぐのがベター。- Java 8以降なら
Optional.ofNullable(list).orElse(List.of())でもOK。
ベストプラクティス②
✅ 例外をループ単位で握りつぶさない設計(ログ付き)
import java.util.List;
import java.util.logging.Logger;
public class SafeApiCall {
private static final Logger logger = Logger.getLogger(SafeApiCall.class.getName());
public static void main(String[] args) {
List<String> urls = List.of(
"https://api.example.com/user",
"https://api.example.com/order",
"https://api.example.com/item"
);
for (String url : urls) {
try {
callApi(url);
logger.info(() -> "✅ 成功: " + url);
} catch (Exception e) {
logger.warning(() -> "⚠️ 失敗: " + url + " → " + e.getMessage());
}
}
logger.info("すべてのAPI呼び出し完了。");
}
static void callApi(String url) throws Exception {
if (url.contains("order")) throw new Exception("Timeout error");
}
}
Java🧠 ポイント
- 拡張
forの中にtry-catchを入れるのが定石。 - 1件失敗してもループ全体を止めない(「部分成功」戦略)。
loggerは SLF4J / java.util.logging などでOK。- 実務では
System.out.printlnより 構造化ロギング が推奨。
ベストプラクティス③
✅ ループ中で例外発生時に再試行(リトライ付き)
import java.util.List;
import java.util.logging.Logger;
public class RetryExample {
private static final Logger logger = Logger.getLogger(RetryExample.class.getName());
public static void main(String[] args) {
List<String> servers = List.of("A", "B", "C");
for (String server : servers) {
int retryCount = 0;
boolean success = false;
do {
try {
sendData(server);
logger.info(() -> "送信成功: " + server);
success = true;
} catch (Exception e) {
retryCount++;
logger.warning(() -> String.format(
"失敗[%s] リトライ回数: %d / 3 - %s", server, retryCount, e.getMessage()
));
}
} while (!success && retryCount < 3);
if (!success) {
logger.severe(() -> "❌ 3回失敗したためスキップ: " + server);
}
}
}
static void sendData(String server) throws Exception {
if (server.equals("B")) throw new Exception("接続エラー");
}
}
Java🧠 ポイント
- 安全な「リトライ+ログ付き」のテンプレート構造。
do-while× 拡張forの組み合わせは実務で非常に多い。- **「リトライ上限を必ず設ける」**ことが大切(無限ループ防止)。
ベストプラクティス④
✅ 例外を集約して後でまとめて処理(監査ログ・エラー一覧用)
import java.util.ArrayList;
import java.util.List;
public class AggregateErrors {
public static void main(String[] args) {
List<String> files = List.of("data1.csv", "data2.csv", "broken.csv");
List<String> errors = new ArrayList<>();
for (String file : files) {
try {
processFile(file);
System.out.println("OK: " + file);
} catch (Exception e) {
errors.add(file + " → " + e.getMessage());
}
}
if (!errors.isEmpty()) {
System.err.println("=== エラー一覧 ===");
errors.forEach(System.err::println);
}
}
static void processFile(String filename) throws Exception {
if (filename.contains("broken")) throw new Exception("ファイルが壊れています");
}
}
Java🧠 ポイント
- 業務システムでは「最後にエラーリストをまとめて通知」することが多い。
- 1件ずつログを出す+最後にサマリーを出す のがよくある設計。
errorsを別の監査テーブルやメール通知に流す構成にも対応可能。
ベストプラクティス⑤
✅ ループ変数を安全に扱う(書き換えない・再利用しない)
import java.util.List;
public class SafeVariableExample {
public static void main(String[] args) {
List<String> users = List.of("Alice", "Bob", "Carol");
for (String user : users) {
// NG例:user を直接書き換えても元リストは変わらない
user = user.toUpperCase(); // ローカル変数だけ変わる
System.out.println(user);
}
System.out.println("元リスト: " + users);
}
}
Java出力:
ALICE
BOB
CAROL
元リスト: [Alice, Bob, Carol]
🧠 ポイント
for-eachの変数は「コピー」です。元データは不変。- 元のリストを更新したい場合は:
for (int i = 0; i < users.size(); i++) { users.set(i, users.get(i).toUpperCase()); } - 読み専用で使うのが基本。
ベストプラクティス⑥
✅ ロギングの粒度を分ける(INFO / WARNING / SEVERE)
実務でログを「あとで追跡できるように」するための設計:
| レベル | 用途例 | 出力例 |
|---|---|---|
| INFO | 正常な処理の進行記録 | 「送信成功」「開始」「完了」 |
| WARNING | 一時的な失敗・再試行・軽微な問題 | 「リトライ1回目失敗」 |
| SEVERE | 致命的エラー・処理中断 | 「API呼び出し不可」「DB接続失敗」 |
ベストプラクティス⑦
✅ 早期終了と continue / break の使い分け
for (String s : List.of("A","B","C","STOP","D")) {
if (s.equals("STOP")) {
System.out.println("⚠️ STOP に到達、処理終了");
break; // ループ全体を抜ける
}
System.out.println("処理中: " + s);
}
🧠 ポイント
- 異常値や終了条件が来たら早めに抜ける。
- 「次だけスキップ」は
continue;を使う。 - 実務では「検査中断」や「入力不正スキップ」に頻出。
総まとめ(実務での安全設計チェックリスト)
| チェック項目 | 推奨方法 |
|---|---|
| ❌ nullリストの走査 | ✅ nullチェック or Optionalで空リストに置き換え |
| ❌ 例外でループ脱落 | ✅ try-catchをループ内に設ける |
| ❌ 無限リトライ | ✅ 上限回数+ログ出力 |
| ❌ 例外握り潰し | ✅ ログ or エラーリストに蓄積 |
| ❌ 書き換え操作 | ✅ 読み専用で使用、更新は通常for |
| ✅ ログレベル | INFO, WARNING, SEVEREで分類管理 |
実務テンプレ(安全構造の基本形)
この1枚をテンプレとしてプロジェクトで使えます。
for (T item : Optional.ofNullable(items).orElse(List.of())) {
try {
process(item);
logger.info(() -> "処理成功: " + item);
} catch (RetryableException e) {
handleRetry(item, e);
} catch (Exception e) {
logger.warning(() -> "処理失敗: " + item + " → " + e.getMessage());
errorList.add(item);
}
}
Java