Stream API 中間操作の flatMap、distinct、limit、skip について使い方をまとめました。
flatMap:変換 ( 1:N )
引数:Function<T, Stream<R>> / 戻り値:Stream<R>
flatMapはmapメソッドと似ていますがFunction<T, Stream<R>>
を引数に取り、要素TからStream<R>を生成します。何を言ってるのかというとmapメソッドの場合は入力と出力が 1:1「(T) -> R」になりますが、flatMapメソッドの場合は 1:N「(T) -> Stream<R>」となり、Rを複数返します。0個でも大丈夫です。
flatMapの使い方
IntegerのListを各数値の数だけ出力するサンプルです。
List<Integer> list = Arrays.asList(1, 2, 3); // ラムダ式 list.stream().flatMap(i -> Stream.generate(() -> i).limit(i)).forEach(System.out::print); // 匿名クラス list.stream().flatMap(new Function<Integer, Stream<Integer>>(){ @Override public Stream<Integer> apply(Integer i) { return Stream.generate(() -> i).limit(i); } }).forEach(System.out::print); // 実行結果 122333
flatMapメソッドを最初見た時は、正直使い道が思い浮かびませんでしたが、調べてみると従来の多重ループを実現することが出来るようです。
今までのfor文で書くと以下のような形になりますが、
for(int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { System.out.println(i + ":" + j); } }
flatMapを使用することで以下のように記述できます。しかし、これは可読性が良くないのであまり使わないかもしれません。
IntStream.range(0, 4).boxed() .flatMap(i -> IntStream.range(0, 4).boxed() .map(j -> i + ":" + j)) .forEach(System.out::println);
defaultメソッド
関数型インターフェースがmapメソッドと同じくFunctionなので、デフォルトメソッドも同様にcompose
andThen
identity
の3種類が使用できます。
プリミティブ型のmapメソッド
flatMapを使用してプリミティブ型のStreamに変換したい場合は、次のflatMapを使用します。
メソッド | 引数 | 戻り値 |
---|---|---|
flatMapToInt | Function<T, IntStream> | IntStream |
flatMapToLong | Function<T, LongStream> | LongStream |
flatMapToDouble | Function<T, DoubleStream> | DoubleStream |
distinct:集約
引数:なし / 戻り値:Stream<T>
distinctメソッドは重複した値を除去して集約した結果のStreamを返します。重複の判定はObject#equals
で行われます。
distinctの使い方
List<Integer> lists = Arrays.asList(100, 100, 200, 200, 300); lists.stream().distinct().forEach(System.out::print); // 実行結果 100200300
limit : 制御
引数:long / 戻り値:Stream<T>
Streamで返す件数を指定します。
limitの使い方
String str = Stream.iterate("a", c -> c + c).limit(5).collect(Collectors.joining(", ")); System.out.println(str); // 実行結果 a, aa, aaaa, aaaaaaaa, aaaaaaaaaaaaaaaa
skip : 読み飛ばす
引数:long / 戻り値:Stream<T>
読み込んだStreamを何件読み飛ばすか指定します。
skipの使い方
String str2 = Stream.iterate("a", c -> c + c).skip(2).limit(5).collect(Collectors.joining(", ")); System.out.println(str2); // 実行結果 aaaa, aaaaaaaa, aaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
関連記事
Java8のforEachを使った繰り返し処理について - TASK NOTES
Java8のStream APIの使い方(Streamの生成編)
Java8のStream APIの使い方(中間操作編① - filter, map)
Java8のStream APIの使い方(中間操作編③ - sorted, peek)
Java8のStream APIの使い方(終端操作編① - anyMatch, allMatch, noneMatch) - TASK NOTES