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);
}
}
Javarange は 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 の置き換えに使うと短く安全なコードになる。
