Stream API でのメニューリファクタリング
ここからは少し応用編です。1ページ目のユーザー入力付きメニューを Stream API でリファクタリングして、よりモダンなJava設計にしてみましょう。
Stream API は本来「コレクションのデータ処理」を簡潔に書くための機能ですが、メニューの処理も「リスト+マッピング」で整理できます。
1. 考え方
- メニュー番号と処理を
Map<Integer, Runnable>で対応付ける switch文の代わりに、入力値で Map を検索 → 存在すれば実行- 存在しなければ「無効な番号」と表示
2. コード例
import java.util.*;
import java.util.stream.*;
public class MenuAppStream {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// メニュー番号と処理をマッピング
Map<Integer, Runnable> menuMap = Map.of(
1, () -> System.out.println("→ 商品一覧を表示します。\n"),
2, () -> {
System.out.print("検索したい商品名を入力してください: ");
String keyword = scanner.nextLine();
System.out.println("→ 「" + keyword + "」を検索しました。\n");
},
3, () -> System.out.println("→ 購入手続きに進みます。\n"),
0, () -> {
System.out.println("→ プログラムを終了します。");
}
);
while (true) {
System.out.println("=== メニュー ===");
System.out.println("1: 商品一覧を見る");
System.out.println("2: 商品を検索する");
System.out.println("3: 購入手続きへ進む");
System.out.println("0: 終了する");
System.out.print("番号を選んでください: ");
int choice = -1;
try {
choice = Integer.parseInt(scanner.nextLine());
} catch (NumberFormatException e) {
System.out.println("→ 数字を入力してください。\n");
continue;
}
// Stream APIで処理実行
Optional.ofNullable(menuMap.get(choice))
.ifPresentOrElse(
Runnable::run, // 処理があれば実行
() -> System.out.println("→ 無効な番号です。\n") // なければメッセージ
);
if (choice == 0) break; // 0ならループ終了
}
scanner.close();
}
}
Java3. コード解説(初心者向けにやさしく)
| ポイント | 説明 |
|---|---|
Map<Integer, Runnable> | メニュー番号をキーに、処理(Runnable)を値として登録 |
Optional.ofNullable(menuMap.get(choice)) | 入力番号に対応する処理を取得。なければ null で Optional が空になる |
.ifPresentOrElse(...) | 処理が存在すれば run() 実行、なければ無効番号のメッセージ |
choice == 0 | 0 を入力したらループを終了(プログラム終了) |
scanner.nextLine() | 数字入力のあとに改行を吸収するため、nextInt より nextLine の方が安全 |
4. この設計のメリット
- switch 文不要 → メニュー追加・変更が簡単
menuMap.put(4, () -> System.out.println("新メニュー追加!")); - 関数型スタイルで簡潔 → 処理を個別にラムダで定義できる
- Optional で安全 → 存在しない入力に対して null チェック不要
- 実務応用 → GUIやWebアプリでも「番号やIDに対して処理をマッピングする」考え方はそのまま応用可能
5. さらに応用できるアイデア
- 入力チェックや例外処理をもっと厳密にして、文字列入力にも対応
- メニュー構造を 別クラス(Serviceクラス)に切り出す
- GUIやWebのボタンIDを Map と Runnable で管理するパターンにも応用可能
まとめ
- 従来の
switchは条件が増えると冗長になりがち - Stream API + Map を使うと 可読性・拡張性が高いメニュー管理 が可能
- ラムダ式で処理を登録できるため、プログラムの変更が簡単
もしよければ次のステップとして、Mainクラス+Serviceクラスに分けた実務風メニュー設計も作れます。
これは「この Stream API メニューをさらにきれいに整理する方法」です。
作ってみますか?
