はじめに:「ループ」の選択でコードの運命が変わる
はじめまして、学生エンジニアの@huyunokiです。
プログラミングの基本である「繰り返し処理(ループ)」にはfor、while、そしてJava 8以降のStream APIなど、いくつかの選択肢があります。
- 「どれを使っても動くけど、どれを選べばいいの?」
この疑問を解消しないまま進むとコードが読みにくくなったり、非効率な処理になってしまったりします。
この記事では僕のインターンで理解しきれなったStreamAPIの理解を目的に、それぞれの構文の「得意・不得意」と「モダンな使い分け」を明確にし、あなたが実務で自信を持ってループを選択できるようになることを目指します。
結論:4種類のループの「得意なこと」
まずは結論として、4つの繰り返し構文の基本的な役割と使い分けを一覧で確認しましょう。
| 構文 | 主な用途(得意なこと) | 実務での選択基準 |
|---|---|---|
for |
回数やインデックスを指定して正確に繰り返したい時 | 「何回目か」を知る必要がある時。breakが必要な場合など |
拡張for |
配列やListの要素を順番に取り出したい時 | 「全要素」にアクセスする時。最もシンプルで可読性が高い |
while |
回数ではなく「条件」が満たされるまで繰り返したい時 | 「いつ終わるかわからない処理」(ユーザーの入力待ち、ファイルの読み込みなど) |
StreamAPI |
コレクションの処理・変換・集計をモダンかつ効率的に行いたい時 | 「データの加工」(フィルタリング、マッピングなど)や並列処理 |
実践例:構文とコード例で学ぶ「使い分け」
ここでは4つの構文がどのように記述され、どのような特徴を持つかを比較します。
1, 通常 for文: for (int i = 0; i < N; i++)
| 項目 | 内容 |
|---|---|
| 目的 | インデックス制御が必要な時 |
| 得意 | 逆順処理、特定のステップ数での処理、ループ途中で要素を削除する時 |
| 構造 | for(初期化 ; 継続条件 ; 更新処理) |
よく使う関数・キーワード
| 関数/キーワード | 用途 | 補足 |
|---|---|---|
break |
ループ処理を途中で強制終了する。 | 目的の要素が見つかったときなどに使う |
continue |
現在のループをスキップして次のループに進む | 特定の条件(例:値がnull)の要素を無視したい時に使う。 |
import java.util.List;
public class Main {
public static void main(String[] args) {
List<String> names = List.of("佐藤", "田中", "山本");
// 1, i=0から開始し、iを1ずつ増やしながらリストの長さ分繰り返す
for (int i = 0; i < names.size(); i++) {
// 2, 特定の値だけスキップ
if(names.get(i).equals("田中")){
continue;
}
// 3, インデックスを使って要素を取得
System.out.println(i + ": " + names.get(i) + "さん");
}
}
}
// ↓実行結果↓
// -> 0: 佐藤さん
// -> 2: 山本さん
2, 拡張for文: for (Type element : array)
| 項目 | 内容 |
|---|---|
| 目的 | すべての要素を順番に取り出したい時 |
| 得意 | 可読性。インデックスを意識せず、要素そのものに集中できる |
| 構造 | for(型 要素変数名 : コレクション/配列) |
よく使う関数・キーワード
先ほどのfor文でも出てきたものが同じように使えます
| 関数/キーワード | 用途 | 補足 |
|---|---|---|
break |
ループ処理を途中で強制終了する。 | 目的の要素が見つかったときなどに使う |
continue |
現在のループをスキップして次のループに進む | 特定の条件(例:値がnull)の要素を無視したい時に使う。 |
import java.util.List;
public class Main {
public static void main(String[] args) {
List<String> names = List.of("佐藤", "田中", "山本", "大西");
// 1. リストの全要素を順番に処理
for (String name : names) {
// 2. 要素変数名(name)を使って直接アクセス
if (name.equals("山本")) {
break; // 山本さんが見つかった時点でfor文終了
}
System.out.println(name + "さん");
}
}
}
// ↓実行結果↓
// -> 佐藤さん
// -> 山本さん
注意:拡張For文の中で、リストの要素をremove()などで削除すると実行時エラー(ConcurrentModificationException)が発生します。削除が必要な場合は、必ず通常For文かIteratorを使いましょう。
3, while文: while (condition)
| 項目 | 内容 |
|---|---|
| 目的 | 条件が真である限り処理を繰り返したい時 |
| 得意 | 終了回数が不明確な処理、ユーザー入力待ち、ファイルの末尾までの読み込み |
| 構造 | while({継続条件}) |
よく使う関数・キーワード
| 関数/キーワード | 用途 | 補足 |
|---|---|---|
break |
ループ処理を途中で強制終了する。 | 目的の要素が見つかったときなどに使う |
continue |
現在のループをスキップして次のループに進む | 特定の条件(例:値がnull)の要素を無視したい時に使う。 |
do-while(継続条件) |
条件に関わらず最低一回は実行したい時 | 処理を行った後にループ継続の条件をチェックする |
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String input = "";
// 1. "終了"という文字列が入力されるまでループを継続
while (!input.equals("終了")) {
System.out.print("何か入力してください(終了で停止): ");
input = scanner.nextLine(); // ユーザーの入力を取得
System.out.println("入力されました: " + input);
}
System.out.println("ループを終了します。");
}
}
// ↓実行結果↓
// -> 何か入力してください(終了で停止): 田中
// -> 入力されました: 田中
// -> 何か入力してください(終了で停止): 佐藤
// -> 入力されました: 佐藤
// -> 何か入力してください(終了で停止): 終了
// -> 入力されました: 終了
// -> ループを終了します。
4, Stream API
| 項目 | 内容 |
|---|---|
| 目的 | データ変換、フィルタリング、集計を簡潔に記述したい時 |
| 得意 | 宣言的な記述(何をしたいか)、メソッドチェーンによる処理のパイプライン化、並列処理への移行の容易さ |
| 構造 | コレクション.stream().操作1().操作2().終端処理() |
よく使う関数・キーワード
| 種別 | 関数 | 用途 |
|---|---|---|
| 中間処理 | filter(Predicate) |
特定の条件に合う要素だけを抽出する |
| 中間処理 | map(Function) |
各要素を別の形式に変換する(例:String→int、大文字化など) |
| 中間処理 | sorted() |
要素をソートする |
| 終端処理 | forEach(Consumer) |
処理後の要素を一つずつ取り出して実行する(出力など) |
| 終端処理 | collect(Collector) |
ストリームの結果をListやMapなどのコレクションにまとめる |
| 終端処理 | count() |
処理後の要素の総数をカウントする |
| 終端処理 | anyMatch(Predicate) |
一つでも条件に合う要素があるか判定する |
import java.util.List;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) {
List<String> names = List.of("佐藤", "田中", "山本", "板倉", "大西", "山田");
// 1, フィルタリングとマッピングと出力
names.stream()
.filter(name -> name.length() == 2) // 1. 文字数が2文字の名前だけを抽出
.map(name -> name + "さん") // 2. 各要素に「さん」をつけて変換
.forEach(System.out::println); // 3. 終端処理(出力)
// ↓実行結果↓
// -> 佐藤さん
// -> 田中さん
// -> 山本さん
// -> 大西さん
// -> 山田さん
// 2, 抽出した結果をListに集計
List<String> filteredList = names.stream()
.filter(name -> name.startsWith("山")) // 「山」から始まる名前を抽出
.collect(Collectors.toList()); // 結果を新しいListに集計
System.out.println("「山」から始まる名前のリスト: " + filteredList);
// ↓実行結果↓
// -> 「山」から始まる名前のリスト: [山本, 山田]
}
}
最後に
最後まで読んでいただき、ありがとうございました!
この記事が皆さんの疑問を解消し、楽しいJava人生になれば幸いです。もし感想や質問があれば、ぜひコメントで教えてください!