【Java】Arrays.streamとStream.ofの違い

Javaで配列を扱う際、「配列をストリーム(Stream)に変換したい」というケースはよくあります。そんなときによく使われるのが Arrays.stream()Stream.of() の2つのメソッドです。

一見似ているこの2つですが、使い方を誤ると「配列の中身を処理したいのに配列そのものが1つの要素になってしまう」といった落とし穴があります。パフォーマンスやバグの観点からも、両者の違いを正しく理解することは非常に重要です。

この記事では、Arrays.stream()Stream.of()の本質的な違いと、どちらを選ぶべきかの判断基準を、具体的なコード例を交えてわかりやすく解説します。

目次

結論:配列の要素を処理したいなら Arrays.stream 一択

まず最初に押さえておくべき結論はシンプルです。

  • 配列の中身(各要素)をストリーム処理したい場合は、Arrays.stream() を使うのが正解です。
  • Stream.of() は配列の種類によって挙動が異なるため、配列処理には不向きです。

この違いを理解していないと、「ループが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[]など)にも対応
  • IntStreamDoubleStreamなどのプリミティブ用のストリームが生成されて効率的

メリット

  • ボクシング不要なので高速(例:intInteger の変換が不要)
  • sum(), average(), max() など、集約系の処理が豊富

実際の使用例

// 配列の要素を加工したい場合
int[] scores = {85, 92, 78, 95};
double average = Arrays.stream(scores)
    .filter(score -> score >= 80)
    .average()
    .orElse(0.0);
System.out.println("平均点: " + average);  // 出力: 平均点: 90.66666666666667

// 文字列配列の処理
String[] names = {"Alice", "Bob", "Charlie"};
Arrays.stream(names)
    .map(String::toUpperCase)
    .forEach(System.out::println);  // 出力: ALICE, BOB, CHARLIE

Arrays.stream() は、配列の内容をストリーム処理したいときの基本かつ最適な選択肢です。特にプリミティブ型の配列を扱う場面では、その恩恵を最大限に受けることができます。

Stream.ofの使い方と特徴

Stream.of() は、複数の値やオブジェクトを手軽にストリーム化できるユーティリティメソッドです。可変長引数(varargs)に対応しており、指定した値をそのままストリームの要素として扱えます。

Stream<String> stream = Stream.of("A", "B", "C");
stream.forEach(System.out::println);  // 出力: A, B, C

主な特徴

  • 可変長引数(Varargs)を受け取るため、複数の要素を直接指定できる
  • 配列を渡した場合の挙動が配列の型によって異なる

配列を渡した場合の挙動

プリミティブ配列の場合

int[] nums = {1, 2, 3};
Stream<int[]> stream = Stream.of(nums);
stream.forEach(System.out::println);  // 出力: [I@6073f712(配列のハッシュコード)
System.out.println("要素数: " + Stream.of(nums).count());  // 出力: 要素数: 1

プリミティブ配列は配列全体が1つの要素として扱われます。

参照型配列の場合

String[] strs = {"A", "B", "C"};
Stream<String> stream = Stream.of(strs);
stream.forEach(System.out::println);  // 出力: A, B, C
System.out.println("要素数: " + Stream.of(strs).count());  // 出力: 要素数: 3

参照型配列は可変長引数として展開されるため、各要素がストリームに含まれます。

Stream.ofの適切な使用例

// 複数の値を直接指定してストリームを作成
Stream.of("apple", "banana", "cherry")
    .filter(fruit -> fruit.startsWith("a"))
    .forEach(System.out::println);  // 出力: apple

// 複数の配列を結合したい場合
String[] fruits = {"apple", "banana"};
String[] vegetables = {"carrot", "potato"};
Stream.of(fruits, vegetables)
    .flatMap(Arrays::stream)
    .forEach(System.out::println);  // 出力: apple, banana, carrot, potato

使い分け早見表と判断基準

Arrays.stream()Stream.of() はどちらも配列をストリームに変換できますが、目的に応じて使い分ける必要があります。以下の早見表を参考に、最適なメソッドを選びましょう。

やりたいこと使うメソッド理由・特徴
配列の各要素をストリームに変換したいArrays.stream()各要素が1つずつストリームに展開される
複数の値を直接指定してストリームにしたいStream.of()可変長引数で任意の数の値を渡せる
プリミティブ型配列を効率よく処理したいArrays.stream()IntStream などが生成され高速
複数の配列をまとめて処理したいStream.of() + flatMap()配列単位での操作が可能

ポイントは「配列の中身を処理したいのか、配列そのものを扱いたいのか」です。用途に応じて正しいメソッドを選ぶことで、バグのない意図どおりのコードを書くことができます。

まとめ:ストリーム生成は目的に応じて正しく使い分けよう

JavaのStream APIは非常に強力ですが、その分使い方を誤ると予期しない挙動になることもあります。

配列をストリームに変換したいなら Arrays.stream()、複数の値を直接指定してストリームを生成したいなら Stream.of()。この基本ルールを覚えておくだけで、コードの明確さと安全性が大きく向上します。

重要ポイント
  • プリミティブ配列は必ず Arrays.stream() を使用する
  • 配列の要素を処理したい場合は Arrays.stream() が安全
  • Stream.of() は値を直接指定する場合に使用し、配列処理は避ける

ストリーム生成時は「何をストリームに変換したいのか?」を明確にし、それに合ったメソッドを選びましょう。そうすることで、バグのない明確でメンテナンス性の高いコードを書くことができます。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次