はじめに
Javaで配列を扱う際、「配列をストリーム(Stream)に変換したい」というケースはよくあります。そんなときによく使われるのが Arrays.stream()
と Stream.of()
の2つのメソッドです。
一見似ているこの2つですが、使い方を誤ると「配列の中身を処理したいのに配列そのものが1つの要素になってしまう」といった落とし穴があります。パフォーマンスやバグの観点からも、両者の違いを正しく理解することは非常に重要です。
この記事では、Arrays.stream()
とStream.of()
の本質的な違いと、どちらを選ぶべきかの判断基準を、具体的なコード例を交えてわかりやすく解説します。
結論:配列の要素を処理したいなら Arrays.stream 一択
まず最初に押さえておくべき結論はシンプルです。
- 配列の中身(各要素)をストリーム処理したい場合は、
Arrays.stream()
を使うのが正解です。 Stream.of()
は配列全体を「1つの要素」として扱うため、要素ごとの処理には不向きです。
この違いを理解していないと、「ループが1回しか回らない」「要素が出力されない」といった意図しない挙動につながる可能性があります。迷ったときは、「何をストリームにしたいのか?」を明確にし、用途に合ったメソッドを選びましょう。
Arrays.streamの使い方と特徴
Arrays.stream()
は 配列からストリームを生成するための専用メソッドです。特に配列の中身を1つずつ処理したい場合に適しています。
int[] nums = {1, 2, 3};
IntStream stream = Arrays.stream(nums);
stream.forEach(System.out::println); // 出力: 1, 2, 3
主な特徴
- 各配列要素をそのままストリーム要素に変換
- プリミティブ型(
int[]
,double[]
など)にも対応 IntStream
、DoubleStream
などのプリミティブ用のストリームが生成されて効率的
メリット
- ボクシング不要なので高速(例:
int
→Integer
の変換が不要) sum()
,average()
,max()
など、集約系の処理が豊富
Arrays.stream()
は、配列の内容をストリーム処理したいときの基本かつ最適な選択肢です。特にプリミティブ型の配列を扱う場面では、その恩恵を最大限に受けることができます。
Stream.ofの使い方と特徴
Stream.of()
は、複数の値やオブジェクトを手軽にストリーム化できるユーティリティメソッドです。可変長引数(varargs)に対応しており、指定した値をそのままストリームの要素として扱えます。
Stream<String> stream = Stream.of("A", "B", "C");
stream.forEach(System.out::println); // 出力: A, B, C
主な特徴
- 可変長引数(Varargs)を受け取るため、複数の要素を直接指定できる
- 配列を渡した場合、その配列全体が1つの要素として扱われる
注意点:配列の扱い
int[] nums = {1, 2, 3};
Stream<int[]> stream = Stream.of(nums);
stream.forEach(System.out::println); // 出力: [I@6073f712
このように、配列を渡しても中身は展開されず、配列オブジェクトそのものが1要素になります。
String[] strs = {"A", "B", "C"};
Stream<String> stream = Stream.of(strs);
stream.forEach(System.out::println); // 出力: A, B, C
参照型の配列(String[]
など)を Stream.of()
に渡すと期待通りになります。
これは内部的に Arrays.stream()
が呼び出されているわけではなく、Stream.of(T... values)
の T
が String
で、可変長引数として展開されているためです。つまり、Stream.of(strs)
と書いた場合、Javaは Stream.of("A", "B", "C")
と同じ意味に解釈してくれます(参照型の配列はvarargsとして展開されるため)。
プリミティブ配列との違いで混乱することを避けるため、配列からStreamへの変換はArrays.stream()
を利用することをおすすめします。
使い分け早見表と判断基準
Arrays.stream()
と Stream.of()
はどちらも配列をストリームに変換できますが、目的に応じて使い分ける必要があります。以下の早見表を参考に、最適なメソッドを選びましょう。
やりたいこと | 使うメソッド | 理由・特徴 |
---|---|---|
配列の各要素をストリームに変換したい | Arrays.stream() | 各要素が1つずつストリームに展開される |
配列全体を1つの要素として扱いたい | Stream.of() | 配列全体が1つの要素になる |
複数の値を直接指定してストリームにしたい | Stream.of() | 可変長引数で任意の数の値を渡せる |
プリミティブ型配列を効率よく処理したい | Arrays.stream() | IntStream などが生成され高速 |
ポイントは「配列の中身を処理したいのか、配列そのものを扱いたいのか」です。用途に応じて正しいメソッドを選ぶことで、バグのない意図どおりのコードを書くことができます。
まとめ:ストリーム生成は目的に応じて正しく使い分けよう
JavaのStream APIは非常に強力ですが、その分使い方を誤ると予期しない挙動になることもあります。
配列をストリームに変換したいなら Arrays.stream()
、ストリームを直接生成もしくは配列全体を1つの要素として扱いたいなら Stream.of()
。この基本ルールを覚えておくだけで、コードの明確さと安全性が大きく向上します。
ストリーム生成時は「何をストリームに変換したいのか?」を明確にし、それに合ったメソッドを選びましょう。そうすることで、バグのない明確でメンテナンス性の高いコードを書くことができます。