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の内容を順に「, 要素値」で連結していくという意味になります。






