Java 逆引き集 | range / rangeClosed(数値ストリーム) — 反復生成

Java Java
スポンサーリンク

range / rangeClosed(数値ストリーム) — 反復生成

IntStream/LongStream には数値の連続を作るための range 系メソッドがあり、for ループより短く安全に「開始〜終了」を生成できます。range は上限を含まず、rangeClosed は上限を含みます。使い分けを押さえると境界バグを減らせます。


しくみと違い(start と end の扱い)

  • range(startInclusive, endExclusive):
    ラベル: 開始は含む・終了は含まない(半開区間)。例えば range(1, 5) は 1,2,3,4 を生成。
  • rangeClosed(startInclusive, endInclusive):
    ラベル: 開始も終了も含む(閉区間)。rangeClosed(1, 5) は 1,2,3,4,5 を生成。
  • 対象ストリーム:
    ラベル: IntStream/LongStream に用意される便利な生成メソッド。for の代替としてよく使われる。

公式 API でも「プリミティブ専用の集約を支えるストリーム」で、range/rangeClosed による連続生成が示されています。


基本コード例(すぐ試せる)

import java.util.stream.IntStream;
import java.util.stream.LongStream;

public class RangeBasics {
    public static void main(String[] args) {
        // 上限を含まない
        int sum = IntStream.range(1, 5).sum();         // 1+2+3+4 = 10
        // 上限を含む
        int sumClosed = IntStream.rangeClosed(1, 5).sum(); // 1+2+3+4+5 = 15

        // LongStream でも同様
        long product = LongStream.rangeClosed(1, 5)
                                 .reduce(1L, (a, b) -> a * b); // 120

        System.out.println(sum + ", " + sumClosed + ", " + product);
    }
}
Java

range は end を含まない、rangeClosed は含むという違いが最大のポイントです。


例題で理解する

例題1: 1〜100 の合計(境界の違いを体感)

int a = IntStream.range(1, 100).sum();        // 1..99 = 4950
int b = IntStream.rangeClosed(1, 100).sum();  // 1..100 = 5050
System.out.println(a + " / " + b);
Java
  • ポイント: 「含む/含まない」の違いで結果が変わる。半開区間は off-by-one のバグを避けやすい。

例題2: ページ番号の生成(1〜N)

int pages = 5;
var list = IntStream.rangeClosed(1, pages).boxed().toList(); // [1,2,3,4,5]
System.out.println(list);
Java
  • ポイント: ユーザーに見せる「1始まり」は rangeClosed が直感的。

例題3: 0〜N-1 のインデックス処理

String[] arr = {"A","B","C","D"};
IntStream.range(0, arr.length)
         .forEach(i -> System.out.println(i + ":" + arr[i]));
Java
  • ポイント: 配列・リストのインデックスは 0 始まりなので range が自然。

実務のコツ(落とし穴回避)

  • 境界バグを防ぐ:
    ラベル: インデックスには range(上限未満)、人間向けの連番には rangeClosed(上限含む)を選ぶと読みやすい。
  • プリミティブの利点:
    ラベル: IntStream/LongStream はオートボクシング不要で軽量。sum/average/max/min が直に使える。
  • 大きな範囲:
    ラベル: int を超える可能性があるなら LongStream を選ぶ。計測して過剰生成を避ける。

テンプレート集(そのまま使える形)

  • 0〜n-1 の反復(配列/リスト)
IntStream.range(0, n).forEach(i -> use(i));
Java
  • 1〜n の連番(表示・ページ)
IntStream.rangeClosed(1, n).forEach(i -> show(i));
Java
  • 区間のフィルタ+集計(偶数の平方和)
int s = IntStream.rangeClosed(a, b)
                 .filter(x -> x % 2 == 0)
                 .map(x -> x * x)
                 .sum();
Java
  • Long 範囲の件数カウント(100000 間隔)
long cnt = LongStream.rangeClosed(1, 1_000_000)
                     .filter(x -> x % 100_000 == 0)
                     .count();
Java

まとめ

  • range: 開始含む・終了含まない(0〜n-1の反復に最適)。
  • rangeClosed: 開始含む・終了含む(1〜nの連番に最適)。
  • プリミティブストリーム: ボクシングなしで高速、集計が直感的。for の置き換えに使うと短く安全なコードになる。
タイトルとURLをコピーしました