Java 逆引き集 | Stream.iterate(Java 9 の変化) — シーケンス生成

Java Java
スポンサーリンク

Stream.iterate(Java 9 の変化) — シーケンス生成

Java 8 から導入された Stream.iterate は「初期値から次の値を生成していく」ための便利なメソッドです。
Java 9 で 終了条件を指定できるオーバーロード が追加され、無限ストリームを安全に有限化できるようになりました。


基本の仕組み

  • Java 8 の iterate:Stream.iterate(seed, unaryOperator)
    • 初期値 seed から始め、unaryOperator を繰り返し適用して次の値を生成。
    • 無限ストリームになるので、必ず limit などで有限化する必要がある。
  • Java 9 の iterate(終了条件付き):Stream.iterate(seed, hasNextPredicate, unaryOperator)
    • hasNextPredicate で「続けるかどうか」を判定できる。
    • 終了条件を組み込めるので、limit を使わずに有限ストリームを作れる。

基本コード例

Java 8 スタイル(無限 → limit)

Stream<Integer> s = Stream.iterate(1, n -> n + 1); // 1,2,3,4,...
List<Integer> list = s.limit(5).toList();
System.out.println(list); // [1, 2, 3, 4, 5]
Java

Java 9 スタイル(終了条件付き)

Stream<Integer> s = Stream.iterate(1, n -> n <= 5, n -> n + 1);
List<Integer> list = s.toList();
System.out.println(list); // [1, 2, 3, 4, 5]
Java

例題で理解する

例題1: フィボナッチ数列(Java 8 スタイル)

Stream.iterate(new int[]{0,1}, a -> new int[]{a[1], a[0]+a[1]})
      .limit(10)
      .map(a -> a[0])
      .forEach(System.out::println);
// 0 1 1 2 3 5 8 13 21 34
Java
  • ポイント: 配列で「前の値・次の値」を保持しながら生成。

例題2: 1〜100 の偶数(Java 9 スタイル)

Stream<Integer> evens = Stream.iterate(2, n -> n <= 100, n -> n + 2);
evens.forEach(System.out::println);
Java
  • ポイント: 終了条件を指定できるので limit 不要。

例題3: 文字列を繰り返し加工

Stream.iterate("A", s -> s.length() < 5, s -> s + "A")
      .forEach(System.out::println);
// A, AA, AAA, AAAA
Java
  • ポイント: 文字列でも利用可能。終了条件で長さを制御。

テンプレート集

  • 無限ストリーム → limit
Stream.iterate(seed, f).limit(n).forEach(...);
Java
  • 終了条件付き(Java 9+)
Stream.iterate(seed, cond, f).forEach(...);
Java
  • フィボナッチ数列
Stream.iterate(new int[]{0,1}, a -> new int[]{a[1], a[0]+a[1]})
      .limit(n)
      .map(a -> a[0])
      .toList();
Java
  • 偶数列(終了条件付き)
Stream.iterate(2, x -> x <= max, x -> x+2).toList();
Java

落とし穴と回避策

  • Java 8 の iterate は無限: 必ず limit を付けないと延々と生成してしまう。
  • 終了条件の誤り: Java 9 の iterate では hasNextPredicate が false になると終了。条件を正しく書く。
  • 複雑な状態管理: 2つ以上の値を扱う場合は配列や小さなクラスで保持する。
  • パフォーマンス: 大量生成はメモリに溜め込まず、逐次処理(forEach)で消費する。

まとめ

  • Java 8: Stream.iterate(seed, f) → 無限ストリーム、limit 必須。
  • Java 9: Stream.iterate(seed, cond, f) → 終了条件付きで有限ストリームを直接生成可能。
  • 用途: 数列生成、状態遷移、文字列加工など「次の値を逐次生成」する場面に便利。

👉 練習課題: 「Stream.iterate を使って 1〜50 の平方数を生成」してみると、Java 8 と Java 9 の違いが直感で理解できます。

タイトルとURLをコピーしました