StreamAPIについて調べてみた peek編 その1

【前提条件】

[環境]

【概要】

今回はpeekについて調べてみました。

peekはStream内にある要素に対して
追加的に処理を行い他時に使用するメソッドです。

【peekメソッド】

[サンプルソース]
    public static void main(final String[] args) {

        final List<Integer> list = new ArrayList<>();

        list.add(1);
        list.add(2);
        list.add(3);

        final int sumValue = 
                list.stream()
                    .peek(v -> System.out.println("debug! [" + v + "]"))
                    .collect(Collectors.summingInt(v -> v));

        System.out.println(sumValue);
    }

peekメソッドはConsumerオブジェクトをパラメータとして受け取ります。
Consumerなのでパラメータを受け取り、戻り値がない関数オブジェクトになります。

サンプルではStream内の要素を出力させています。

[出力結果]
debug! [1]
debug! [2]
debug! [3]
6

【考察】

peekメソッドはConsumer関数なので、
副作用を伴う処理を行う場合に使うものです。

[サンプルソース]
    public static void executeStringBuilderList() {

        final List<StringBuilder> list = new ArrayList<>();

        list.add(new StringBuilder("one"));
        list.add(new StringBuilder("two"));
        list.add(new StringBuilder("three"));

        list.stream()
            .peek(v -> v.append("-value"))
            .forEach(v -> System.out.println(v.toString()));
    }

副作用を伴う処理の例です。
ListにStringBuilderを入れているて、peek内で値を書き換えています。
(普通はこのようなコードは書かないと思いますがサンプルなので)

[出力結果]
one-value
two-value
three-value

「mapとかでも同じことできるじゃん」と思うかもしれません。

確かにmapでも同じことはできるのですが、
Stream内の要素を別の型に変えることが主な役割なので
その処理内で副作用があるのは好ましいとは思いません。

「mapなのに中の値が書き換わってる」と言いながらバグ調査することになると思います。
getterなのに値が書き換わるとかそういうのと同じかなと思います。

Streamの処理内で副作用を伴う処理を実行したい場合は
明示的にpeekメソッドで実行したほうが読みやすくなると思います。

【まとめ】

peekメソッドは副作用を伴う処理を
実行させる時に使うと良いと思います。

デバッグログを出力したいと言う場合には重宝するメソッドかなと思います。