Streamの終端処理
終端処理では、Stream内で加工/フィルターされた値を最終的に出力/集計します。Streamでは、中間処理の時点では処理をストックします。そして、終端処理が呼び出されたところでまとめて加工/フィルターなどを実施します(遅延処理)。その性質上、中間処理は省略可能ですが、終端処理は末尾で必ず呼び出さなければなりません。
要素を順に処理する – forEachメソッド- public void forEach(Consumer<? super T> action)
- T:要素の型
- action:個々の要素を処理するラムダ式
たとえば以下は、Streamの内容を順に出力する例です。
StreamForEach.java
\package com.example.mynavi.streamapi; import java.util.stream.Stream; public class StreamForEach { public static void main(String[] args) { Stream.of("あいうえお", "かきくけこ", "さしすせそ") .forEach(System.out::println); } }
▼
あいうえお かきくけこ さしすせそ
forEachメソッドは、「個々の要素を引数として受け取り、これを処理する(戻り値はなし)」ラムダ式を受け取ります。printlnメソッドは、引数をひとつ受け取り、戻り値がvoidなので、そのままforEachメソッドに渡せるわけです(メソッドそのものを渡す表現を、メソッド参照と呼びます)。
よって、サンプルの太字部分は以下のように書き換えても同じ意味です。
.forEach(s -> System.out.println(s));
- public boolean anyMatch(Predicate<? super T> predicate)
- public boolean allMatch(Predicate<? super T> predicate)
- public boolean noneMatch(Predicate<? super T> predicate)
- T:要素の型
- predicate:条件式を表すラムダ式
anyMatchメソッドは条件式を満たす要素がひとつでもある場合、allMatchメソッドはすべての要素が条件式を満たす場合、そして、noneMatchメソッドはひとつも満たさない場合に、それぞれtrueを返します。
たとえば以下は、Stream内のすべての要素が5文字以上であるかを判定する例です。
StreamMatch.java
\package com.example.mynavi.streamapi; import java.util.stream.Stream; public class StreamMatch { public static void main(String[] args) { System.out.println( Stream.of("あかさか", "さくらぎちょう", "よよぎ") .★allMatch★(v -> v.length() >= 5) ); // 結果:false } }
太字の部分をanyMatch/noneMatchに変更した場合には、それぞれ結果はtrue、falseとなります。
最初の要素だけを取得する – findFirstメソッド- public Optional<T> findFirst()
- T:要素の型
findFirstメソッドを利用することで、Streamから先頭の要素だけを取得できます。
streamFirst.java
\package com.example.mynavi.streamapi; import java.util.stream.Stream; public class streamFirst { public static void main(String[] args) { System.out.println( Stream.of("あかさか", "さくま", "あおし") .filter(s -> s.startsWith("あ")) .findFirst() .orElse("×") ); // 結果:あかさか } }
findFirstメソッドの戻り値は、Optional型です。よって、値を取得するにはorElseなどのメソッドを介さなければなりません。
Streamの内容を集計する- public Optional<T> max(Comparator<? super T> comparator) … 最大値
- public Optional<T> min(Comparator<? super T> comparator) … 最小値
- public long count() … 個数
- public OptionalDouble average() … 平均値
- public int sum() … 合計値
- T:要素の型
- comparator:比較ルールを表すラムダ式
Streamの内容を集計するために、上のようなメソッドを利用できます。ただし、average/sumメソッドが利用できるのは、IntStreamなどの基本型Streamだけです。
たとえば以下は、これらのメソッドを使って数値型Streamの内容を集計する例です。
StreamSum.java
IntStream stream =IntStream.of(15, 7, 38, 50, 1); System.out.printf("最大値:%d\n", stream.max().orElse(0)); //System.out.printf("最小値:%d\n", stream.min().orElse(0)); //System.out.printf("個数:%d\n", stream.count()); //System.out.printf("平均値:%f\n", stream.average().orElse(0)); //System.out.printf("合計値:%d", stream.sum());
▼
最大値:50
結果は1行ずつコメントアウト、コメントを解除した上で確認してください(一旦、終端処理を呼び出したStreamに対して繰り返し終端処理を呼び出すことはできません)。
集計値をまとめて取得したいならば、XxxxxSummaryStatisticsクラスを利用することもできます(XxxxxはInt、Long、Doubleのいずれか)。
StreamStatistics.java
\package com.example.mynavi.streamapi; import java.util.IntSummaryStatistics; import java.util.stream.IntStream; public class StreamSum { public static void main(String[] args) { IntSummaryStatistics summary = IntStream.of(15, 7, 38, 50, 1).collect( IntSummaryStatistics::new, IntSummaryStatistics::accept, IntSummaryStatistics::combine ); System.out.printf("最大値:%d\n", summary.getMax()); System.out.printf("最小値:%d\n", summary.getMin()); System.out.printf("個数:%d\n", summary.getCount()); System.out.printf("平均値:%f\n", summary.getAverage()); System.out.printf("合計値:%d", summary.getSum()); } }
▼
最大値:50 最小値:1 個数:5 平均値:22.200000 合計値:111
collectメソッドは、Streamの内容を束ねるための機能を提供します。独自のラムダ式を渡すこともできますが、数値集計をするならば、太字の記述はイディオムと考えてよいでしょう。
Streamの値をまとめる- public Optional<T> reduce(BinaryOperator<T> accumulator)
- T:要素の型
- accumulator:値を結合するためのラムダ式
reduceメソッドを利用することで、Streamの内容を独自の規則で束ねることができます。たとえば以下は、String型のStreamをタブ区切りでまとめる例です。
StreamReduce.java
\package com.example.mynavi.streamapi; import java.util.stream.Stream; public class StreamReduce { public static void main(String[] args) { System.out.println( Stream.of("あかさか", "さくらぎちょう", "よよぎ") .reduce((result, str) -> result + "\t" + str) .orElse("") ); // 結果:あかさか さくらぎちょう よよぎ } }
引数accumulatorは、引数として
・演算結果を格納するための変数(result。初期値は先頭の要素)
・個々の要素を受け取る変数(str)
を受け取るラムダ式です。引数resultの内容はStreamを通じて引き継がれるので、この例であれば、Streamの内容を順に「, 要素値」で連結していくという意味になります。