ストリームAPIとは?
-
ストリームAPIとはJava SE 8でコレクションをより扱いやすくするために導入された拡張機能です。
「java.util.stream.Streamインタフェース」に定義されています。コレクションの各要素に対して行う処理をメソッドとラムダ式で記述することで、コードを簡潔に表現できます✨ -
「ストリーム」という概念は入出力処理で聞き覚えがあると思いますが、そのストリームとは全く異なる概念です。ストリームAPIでは、コレクションの各要素を処理していく「流れ」と捉えて、コレクションを「ストリーム」という概念で扱います。
-
処理は「ストリームの生成」「中間操作」「終端操作」に分けられます
0個以上の中間操作と1つの終端操作を組み合わせたものを「ストリーム・パイプライン」と呼びます。1つのストリーム・パイプラインに対して、中間操作は何度でも実行でき、終端操作は1回のみ実行できます。(終端操作は2回以上実行するとIllegalStateExceptionがスローされます。)
注意点
ストリームAPIはfor文などの繰り返し構文を置き換えるために用意された表現ではありません。
繰り返し構文ではローカル変数の読み書きが自由に行えますが、ストリームのラムダ式からはfinalもしくは実質的にfinalなローカル変数のみ扱うことができます。ストリーム・パイプライン内からローカル変数の値を変更することはできません。
またfor文などの繰り返し処理ではreturnやbreak、continue、もしくは例外のスローによって処理の流れを制御することができますが、ストリームのラムダ式からは処理の流れを制御することはできません。
1. ストリームの生成
リストからストリームを生成する
java.util.Collection
メソッド | 戻り値 | 概要 |
---|---|---|
stream() | Stream<E> | ストリームを生成する。 java.util.Collectionインタフェースのデフォルトメソッド。 |
pararellStream() | Stream<E> | 並列ストリームを生成する。 java.util.Collectionインタフェースのデフォルトメソッド。 |
配列からストリームを作成する
java.util.stream.BaseStreamです。
java.util.Arrays
メソッド | 戻り値 | 概要 |
---|---|---|
stream(T[] array) | Stream<T> | 配列からストリームを生成する |
stream(int[] array) | IntStream | 配列からIntStream型のストリームを生成する |
stream(long[] array) | LongStream | 配列からLongStream型のストリームを生成する |
stream(double[] array | DoubleStream | 配列からDoubleStream型のストリームを生成する |
2. 中間操作とは
中間操作とは、取り出した要素に処理を行うことです。
いくつも繋げることができますが、終端操作を実行したタイミングで実行するのが特徴です。
java.util.stream.Stream
メソッド | 概要 |
---|---|
distinct() | 要素の重複(Objects.equalsがtrueになる)を除いたストリームを戻す |
filter(Predicate super T> predicate) | 引数に指定した条件に一致する要素だけで構成されるストリームを戻す |
limit(long maxSize) | ストリームの要素を指定された数に切り詰めた結果のストリームを戻す |
map(Function super T,? extends R> mapper) | 指定された関数を要素に適用した結果のストリームを戻す ※入力され多少その集合の型と出力の集合の方は一致していなくても良い🙆🏻♂️ |
peek(Consumer super T> action) | 新しい結果のストリームを生成し、指定された関数を適用して戻す |
skip(long n) | 引数で指定した最初のn個の要素を破棄し、残った要素で構成されるストリームを戻す |
sorted(Comparator super T> comparator) | このストリームの要素を自然順序に従ってソートした結果から構成されるストリームを戻す |
3. 終端操作とは
- 終端操作とは、処理を加えた要素の集合に対して処理を行うことです。
- 終端操作の内、一連の要素を1つにまとめる操作を「リダクション操作」と呼びます。
java.util.stream.Stream
メソッド | 戻り値 | 概要 |
---|---|---|
allMatch(Predicate super T> predicate) | boolean | ストリーム内のすべての要素が条件に一致するかどうかを調べる |
anyMatch(Predicate super T> predicate) | boolean | ストリーム内のいずれかの要素が条件に一致するかどうかを調べる |
collect(Collector<? super T,A,R> collector) | <R,A> R | ストリームの要素を持つコレクションを戻す |
count() | long | ストリーム内の要素を数える |
findAny() | Optional<T> | ストリーム内の最初の要素を持つOptionalを戻す。※並列処理時は常に同じ要素を返すとは限らない |
findFirst() | Optional<T> | ストリーム内の最初の要素を持つOptionalを戻す。※並列処理時も常に同じ要素を返す |
forEach(Consumer super T> action) | void | ストリーム内の要素を使って繰り返し処理を実行する |
forEachOrdered(Consumer<? super T> action) | void | ストリーム内の要素を使って、決められた順番で繰り返し処理を実行する。順番を意識するので、パフォーマンス向上は見込めない。 |
max(Comparator super T> comparator) | Optional<T> | ストリーム内の最大の要素を戻す |
min(Comparator super T> comparator) | Optional<T> | ストリーム内の最小の要素を戻す |
reduce(BinaryOperator accumulator) | Optional<T> | ストリーム内の要素を累積的に結合していくリダクション処理を実行する |
toArray() | Object[] | ストリームの要素を含む配列を戻す |
java.util.stream.Collector
リダクション操作を扱うためのインタフェースです。
メソッド | 戻り値 | 概要 |
---|---|---|
supplier() | Supplier<A> | 処理途中の値を保持する |
accumulator() | BiConsumer<A,T> | 具体的に実行したい処理を記述したBiconsumer型のラムダ式を戻す |
combiner() | BinaryOperator<A> | 並列処理をしている時、個々に作られた処理途中の値を保持するためのオブジェクトを結合する |
finisher() | Function<A,R> | 処理結果を戻すラムダ式を提供する |
characteristics() | Set<Collector.Characteristics> | Collectorの特徴を表すEnumのセットを戻す |
java.util.stream.Collector.Characteristics
列挙子 | 概要 |
---|---|
CONCURRENT | Collectorが並行処理をすることを表す |
IDENTITY_FINISH | COllectorのfinisherメソッドが省略可能であることを表す |
UNORDERED | コレクションの操作において順序の維持を保証しないことを表す |
Collectorインタフェースの実現クラスが「java.util.stream.Collectorsクラス」です。要素をコレクションに蓄積したり、様々な条件に従って要素を要約したりすることができる便利なクラスです。
java.util.stream.Collectors
メソッド | 戻り値 | 概要 |
---|---|---|
toList() | Collector<T,?,List<T>> | ストリームの中間操作をして得た結果から新しいリストを作る |
toSet() | Collector<T,?,Set<T>> | ストリームの中間操作をして得た結果から新しいセットを作る |
toMap(Function<? super T,? extends K> keyMapper, Function<? super T,? extends U> valueMapper) | Collector<T,?,Map<K,U>> | ストリームの中間操作をして得た結果から新しいマップを作る。 |
toMap(Function<? super T,? extends K> keyMapper, Function<? super T,? extends U> valueMapper, BinaryOperator<U> mergeFunction) | Collector<T,?,Map<K,U>> | ストリームの中間操作をして得た結果から新しいマップを作る。第3引数でキーが重複した際に先勝ちか後勝ちか指定する。 |
toMap(Function<? super T,? extends K> keyMapper, Function<? super T,? extends U> valueMapper, BinaryOperator<U> mergeFunction, Supplier<M> mapSupplier) | Collector<T,?,M> | ストリームの中間操作をして得た結果から新しいマップを作る。第3引数でキーが重複した際に先勝ちか後勝ちか、第4引数でマップの型を指定する。 |
groupingBy(Function<? super T,? extends K> classifier) | Collector<T,?,Map<K,List<T>>> | ストリームの中間操作をして得た結果を指定したキーでグルーピングし、新しいマップを作る。 |
partitioningBy(Predicate<? super T> predicate) | Collector<T,?,Map<Boolean,List>> | ストリームの中間操作をして得た結果を指定した条件に合致したか否かでグルーピングし、新しいマップを作る |
summingInt(ToIntFunction<? super T> mapper) | Collector<T,?,Integer> | グループ内の要素が持つ数値(int型)の合計値を計算する |
summingLong(ToLongFunction<? super T> mapper) | Collector<T,?,Long> | ループ内の要素が持つ数値(long型)の合計値を計算する |
summingDouble(ToDoubleFunction<? super T> mapper) | Collector<T,?,Double> | ループ内の要素が持つ数値(double型)の合計値を計算する |
averagingInt(ToIntFunction super T> mapper) | Collector<T,?,Double> | ループ内の要素が持つ数値(int型)の平均値を計算する |
averagingLong(ToLongFunction super T> mapper) | Collector<T,?,Double> | ループ内の要素が持つ数値(long型)の平均値を計算する |
averagingDouble(ToDoubleFunction super T> mapper) | Collector<T,?,Double> | ループ内の要素が持つ数値(double型)の平均値を計算する |
参考資料
徹底攻略Java SE 11 Gold問題集