終端処理では、Stream内で加工/フィルターされた値を最終的に出力/集計します。Streamでは、中間処理の時点では処理をストックします。そして、終端処理が呼び出されたところでまとめて加工/フィルターなどを実施します(遅延処理)。その性質上、中間処理は省略可能ですが、終端処理は末尾で必ず呼び出さなければなりません。
要素を順に処理する – forEachメソッド
public void forEach(Consumer<? super T> action)
T:要素の型
action:個々の要素を処理するラムダ式
たとえば以下は、Streamの内容を順に出力する例です。
- 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));
Stream内の値が条件を満たすかを判定する – xxxxxMatchメソッド
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文字以上であるかを判定する例です。
- 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から先頭の要素だけを取得できます。
- 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の内容を集計する例です。
- 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のいずれか)。
- package com.example.mynavi.streamapi;
- import java.util.IntSummaryStatistics;
- import java.util.stream.IntStream;
- public class StreamSum {
- public static void main(String args) {
- var 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をタブ区切りでまとめる例です。
- 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の内容を順に「<タブ>, 要素値」で連結していくという意味になります。
監修