CONTENTS コンテンツ

2022.02.18

【Java】Stream APIの基本

こんにちは!

東京のMKです。

社内ブログを書いていこうかと思うのですが特にネタが思いつかないので、現在勉強しているJavaGoldの中から「Stream API」について紹介していきたいと思います。


 

Stream APIとは

Stream APIは一言で表すと「配列やCollectionなどの集合体を扱う為のもの」です。

値の集計やデータを使った処理などが出来る便利なAPIとしてJavaSE8から新たに導入されました。

Stream APIでは、コレクションの各要素を処理していく「流れ」という意味を込めて、コレクションを「ストリーム」という概念で扱います。

コレクションを扱うときに、要素を一つずつ取り出し何らかの処理を加え、特定の要素だけを取り出したり、配列に変換したり、コレクションを詰め替えたりすることがよくあると思います。

このような処理をStream APIではメソッドとラムダ式で記述することでコードをより簡潔にできます。


使い所

Stream APIの主な使い所は下記のようなことをしたい時です。

・コレクションや配列の全要素を同じように変換する場合

・コレクションや配列の要素の合計や平均といった統計をとる場合

・コレクションや配列の要素を何らかの条件でグルーピンスしたい場合

・コレクションや配列の要素から条件に合ったデータを検索する場合


基本的なメソッド

Stream APIでは取り出した要素に加える処理のことを中間処理と呼び、中間処理を終えた要素の集合に対して行う最終処理を終端処理と呼びます。

基本的には以下のような流れで記述します。

  1. コレクションからStreamを取得
  2. 中間処理を定義(複数記述可能)
  3. 終端処理を定義(最後の一回だけ記述可能)

2, 3のような操作はStream APIの基本となる機能をまとめたjava.util.Streamインターフェースに定義されており次のような種類があります。

 

【中間処理】

処理を行うメソッド 概要
distinct 要素の重複を除いたStreamを戻す
filter 引数に指定した条件に一致する要素だけで構成されるStreamを戻す
limit Streamの要素を、指定された数に切り詰めた結果のStreamを戻す
map 指定された関数を要素に適用した結果のStreamを戻す
peek 新しい結果のStreamを生成し、指定された関数を適用して戻す
skip 引数で指定した最初のn個の要素を破棄し、残った要素で構成されるStreamを戻す
sorted このStreamの要素を自然順序に従ってソートした結果から構成されるStreamを戻す

 

【終端処理】

処理を行うメソッド 概要
allMatch Stream内の全ての要素が条件に一致するか調べる
anyMatch Stream内のいずれかの要素が条件に一致するか調べる
collect Stream内の要素を持つコレクションを戻す
count Stream内の要素を数える
findAny Stream内の要素が残っているかどうかの結果を持つOptional(*1)を戻す
findFirst Stream内の最初の要素を持ったOptional(*1)を戻す
forEach Stream内の要素を使って繰り返し処理を実行する
max Stream内の最大の要素を戻す
min Stream内の最小の要素を戻す
noneMatch Stream内の要素で条件に一致するものがないかどうか調べる
reduce Stream内の要素を累積的に結合していくリダクション処理を実行する
toArray Stream内の要素を含む配列を戻す

 

*1: java.util.Optionalはメソッドの処理結果を扱うためのクラスで、処理結果の正常・異常に関わらず同じ型で扱うことができます。このクラスを使用することにより例外処理に関するコードを簡潔に記述することができます。今回の記事では触れません!


使用例

それでは簡単な使用例を見ていきましょう!

まずは、従来のコレクションの使用方法をおさらいしておきましょう。

次のコード例は、数値のコレクションから偶数の物だけを抜き出し、コンソールに表示するというものです。

public static void main(String[] args) {
        // 従来のコード
	List list = Arrays.asList(2, 18, 3, 49, 54, 19);
	for (Integer num: list) {
		if (num % 2 == 0) {
			System.out.println(num);
		}
	}
}

このコードをStream APIを用いて書き換えたものが次のコードです。

 

public static void main(String[] args) {
        // Stream APIを使用
	List list = Arrays.asList(2, 18, 3, 49, 54, 19);
	list.stream() // listからStreamを取得
	    .filter(num -> num % 2 == 0) // 偶数の値を絞り込りこんで (中間処理)
	    .forEach(x -> System.out.println(x)); // 繰り返し処理を実行 (終端処理)
}

このコードでは、まずList型変数listのstreamメソッドを呼び出して、リストからStreamを生成します。

(ListやSetといったCllectionのサブインターフェースでデフォルトメソッドとして実装されています。)

下記のような形で書くことも可能です。
Stream stream = list.stream();

Streamから偶数の値を絞り込むには中間処理のfilterメソッドを使用します。このメソッドはjava.util.Predicate型の引数を受け取り、ラムダ式で指定された条件に一致するかどうかでstream内の要素を絞り込みます。

その後、終端処理のforEachメソッドを使用してstream内の値をコンソールに出力しています。

コンソールの出力は以下のようになります。

 


終わりに

「Stream API」、いかがだったでしょうか。

コードが簡潔に書けるのでいいなぁとは思いますが、今回紹介させていただいた終端処理のforEachメソッドで言うと、普通のfor文のようにretrunやbreak, continueなどの処理の制御ができないというデメリットもあるみたいなので、使い分けていかないとなと思います。

以上です。最後まで読んでいただき、ありがとうございました!!