Stream生成は「データに“流れ”をつける」入り口
Stream は「コレクションや配列などの要素を、流れとして扱うためのビュー」です。filter や map、collect などの“Stream 操作”を使うためには、まず「Stream をどうやって作るか(生成するか)」を押さえる必要があります。
業務コードでは、ほぼ次のパターンから Stream を作ります。
コレクション(List・Set)から
配列から
単発の値や可変長引数から
数値レンジや乱数などの“連番・無限列”から
ここを整理しておくと、「とりあえず Stream にしてから考える」という書き方ができるようになります。
コレクションからの Stream生成
List・Set からは stream() が基本
Collection(List・Set など)には、stream() メソッドが用意されています。
import java.util.List;
import java.util.stream.Stream;
public class FromCollection {
public static void main(String[] args) {
List<String> names = List.of("山田", "佐藤", "鈴木");
Stream<String> stream = names.stream();
stream
.filter(n -> n.startsWith("佐"))
.forEach(System.out::println); // 佐藤
}
}
Javaここでの重要ポイントは、stream() が「元データをコピーするのではなく、“ビュー”を作るだけ」ということです。
Stream 自体は“使い捨て”で、一度終端操作(forEach や collect など)を呼ぶと再利用できません。
「List で持っておく → 必要なときに list.stream() で流れを作る」というスタイルを基本形として覚えてください。
配列からの Stream生成
参照型配列:Arrays.stream と Stream.of
String[] などの参照型配列から Stream を作る代表的な方法は二つあります。
import java.util.Arrays;
import java.util.stream.Stream;
public class FromArrayRef {
public static void main(String[] args) {
String[] array = {"A", "B", "C"};
Stream<String> s1 = Arrays.stream(array);
Stream<String> s2 = Stream.of(array);
s1.forEach(System.out::println); // A B C
}
}
Java参照型配列に関しては、Arrays.stream も Stream.of も「要素ごとの Stream」を返すので、挙動はほぼ同じです。
ただし、「“配列そのもの”を 1 要素として扱いたい」場合は Stream.of(array)(型は Stream<String[]>)という使い方もあるため、
「配列の中身を流したいのか」「配列自体を流したいのか」を意識して選ぶのが大事です。
プリミティブ配列:Arrays.stream 一択で覚える
int[] などのプリミティブ配列は、Arrays.stream を使うのが基本です。
import java.util.Arrays;
import java.util.stream.IntStream;
public class FromArrayPrimitive {
public static void main(String[] args) {
int[] nums = {1, 2, 3};
IntStream stream = Arrays.stream(nums);
int sum = stream.sum();
System.out.println(sum); // 6
}
}
Javaここでの重要ポイントは二つです。Arrays.stream(int[]) は IntStream を返すので、sum や average など“数値専用の便利メソッド”が使える。Stream.of(nums) だと Stream<int[]> になってしまい、「配列1個が1要素」になってしまうので、配列の中身を処理したいときには不向き。
「配列の要素を処理したいなら、プリミティブでも参照型でも、とりあえず Arrays.stream」と覚えておくと安全です。
単発値・可変長引数からの Stream生成
Stream.of で「その場でちょっとした Stream」を作る
「わざわざ List を作るほどでもないけれど、Stream で書きたい」というときは、Stream.of が便利です。
import java.util.stream.Stream;
public class FromValues {
public static void main(String[] args) {
Stream<String> stream =
Stream.of("山田", "佐藤", "鈴木");
long count =
stream.filter(n -> n.length() == 2)
.count();
System.out.println(count);
}
}
Javaここでの重要ポイントは、Stream.of が「引数に渡した値を、そのまま順番付きの Stream にしてくれる」ことです。
テストコードや、ちょっとした分岐処理などで「3〜4個の候補を Stream で処理したい」ときに、とても書きやすくなります。
数値レンジ・無限列からの Stream生成
IntStream.range / rangeClosed で「連番の Stream」
ループの代わりに「1〜N までの連番」を Stream で扱いたいときは、IntStream.range 系を使います。
import java.util.stream.IntStream;
public class FromRange {
public static void main(String[] args) {
IntStream.range(0, 5) // 0,1,2,3,4
.forEach(System.out::println);
IntStream.rangeClosed(1, 3) // 1,2,3
.forEach(System.out::println);
}
}
Javarange(開始, 終了) は「開始以上、終了未満」、rangeClosed(開始, 終了) は「開始以上、終了以下」です。
for ループの代わりに「インデックスの Stream」を作るイメージで使うと、mapToObj(i -> ...) などと組み合わせて柔軟な処理が書けるようになります。
Stream.generate / iterate で「無限列」
「同じ値を繰り返す」「前の値から次の値を計算する」といった“無限列”も Stream で作れます。
import java.util.stream.Stream;
public class FromInfinite {
public static void main(String[] args) {
Stream.generate(() -> "A")
.limit(3)
.forEach(System.out::println); // A A A
Stream.iterate(1, n -> n + 1)
.limit(5)
.forEach(System.out::println); // 1 2 3 4 5
}
}
Javaここでの重要ポイントは、「必ず limit などで打ち切ること」です。
無限列は強力ですが、終端操作までに“どこかで止める”ことを忘れると、延々と処理が続いてしまいます。
Stream生成ユーティリティで「入口の迷い」を減らす
「とりあえず Stream にする」ための小さなヘルパー
実務では、「null かもしれないコレクション」「配列かもしれないし単体かもしれない値」など、
“そもそも何から Stream を作るか”で毎回 if 文を書きがちです。
そういうときは、入口だけユーティリティに寄せてしまうとスッキリします。
import java.util.Collection;
import java.util.stream.Stream;
public final class Streams {
private Streams() {}
public static <T> Stream<T> from(Collection<T> c) {
if (c == null || c.isEmpty()) {
return Stream.empty();
}
return c.stream();
}
@SafeVarargs
public static <T> Stream<T> ofNullable(T... values) {
if (values == null || values.length == 0) {
return Stream.empty();
}
return Stream.of(values);
}
}
Java使い方のイメージです。
Streams.from(list)
.filter(...)
.forEach(...);
Streams.ofNullable(maybeValue)
.filter(...)
.forEach(...);
Java「null なら空 Stream」「そうでなければ普通の Stream」という入口を一箇所に閉じ込めることで、
呼び出し側は「とにかく Stream として扱う」ことだけに集中できます。
まとめ:Stream生成で身につけてほしい感覚
Stream生成は、
単に「書き方を暗記する」話ではなく、
「データの“持ち方”と“流し方”を分けて考えるための入口設計」です。
コレクションなら collection.stream()、
参照型配列なら Arrays.stream(array)、
プリミティブ配列なら Arrays.stream(primitiveArray)、
単発値なら Stream.of(...)、
連番なら IntStream.range / rangeClosed、
無限列なら Stream.generate / iterate。
このあたりを“手癖”で選べるようになると、
「まず Stream にしてから、filter / map / collect を考える」という書き方が自然にできるようになります。
あなたのコードのどこかに、
同じような for ループが何度も出てきているなら、
一度「その入口を Stream生成に置き換えられないか」を眺めてみてください。
その小さな一歩が、
「データ処理を“流れ”として設計できるエンジニア」への、
確かなステップになります。

