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

【前提条件】

[環境]

【概要】

今回からラムダのメインとも言えるStreamAPIです。

StreamAPIはリストなどで並行処理を行うためのAPIです。
並行処理を行うためのAPIではありますが、
並行処理ではなくても使用できるものです。

StreamAPIでは並行処理を行うための
ベースとなるStreamインターフェイスが提供されています。

今回は各コレクションからStreamオブジェクトを
作成する方法について調べてみました。

【streamメソッド】

Collection#streamメソッドを使用すると
Streamオブジェクトが生成されます。

    final Collection<String> valueList = new ArrayList<>();

    final Stream<String> stream = valueList.stream();

Collectionインターフェイスにメソッドが定義されているため、
Collectionインターフェイスを実装していないMapでは
Mapから直接Streamを作成することはできません。

【StreamAPI】

[StreamAPIの使い方]

Streamインターフェイスは要素内のオブジェクトに対する
操作が定義されています。

StreamAPIはStreamインターフェイス
戻り値のメソッドが多く定義されていて、
メソッドチェインで操作をさせることができます。

    valueList.stream().filter(/* 何かしらの処理 */).collect(/* 何かしらの処理 */);
[Streamからの変換]

StreamAPIで要素内のオブジェクトに操作をした後、
リストなどに変換する必要があります。

まずはStreamオブジェクトからListオブジェクトに変換してみます。

    final List<String> valueList = new ArrayList<>();

    valueList.add("one");
    valueList.add("two");
    valueList.add("three");
    valueList.add("four");
    valueList.add("five");

    final List<String> collectedList = valueList.stream().collect(Collectors.toList());
    collectedList.forEach(System.out::println);

Stream#collectを使うとStreamAPIで操作した結果をリストなどに変換してくれます。
CollectorsクラスにはStreamからListなどに変換するメソッドが定義されています。

サンプルではList⇒Stream⇒Listに変換しているだけなので、
StreamAPIの動きが良くわからないので、
文字列が3文字より多いもののみ抽出してみたいと思います。
valueListの中身は先ほどのサンプルと同じです。

    final List<String> filteredList = 
            valueList.stream().filter(v -> v.length() > 3).collect(Collectors.toList());
    filteredList.forEach(System.out::println);

実行結果はこうなります。

three
four
five

Stream自体はListと紐付いているわけではないので、
List⇒Stream⇒Setと言う形に変換することもできます。

    final Set<String> filteredSet = 
            valueList.stream().filter(v -> v.length() > 3).collect(Collectors.toSet());

【Collectionインターフェイスを実装していないクラス】

List/Set以外でよく使われるMap、配列は
Streamオブジェクトを直接作成することはできません。

一度、Streamオブジェクトを作成できるクラスに変換する必要があります。

[Map]

MapはSetに変換することでStreamを作成できます。

    final Map<String, Integer> valueMap = new LinkedHashMap<>();
    valueMap.put("one", 1);
    valueMap.put("two", 2);
    valueMap.put("three", 3);
    valueMap.put("four", 4);
    valueMap.put("five", 5);

    final List<String> collectedList = valueMap.keySet().stream().collect(Collectors.toList());
    collectedList.forEach(System.out::println);
[Array]

以前のエントリで配列ではforEachするのに
Arrays#asListを使って一度リストに変換すると言うことを書きました。

うらがみさん(@)から
Java 配列はArrays.stream()でStreamに変換してからforEachするという手もありますねー」
と言うコメントをいただきました。
(コメントいただきありがとうございます)

と言うことで早速Array#streamを使ってみます。

    final String[] valueArray = { "one", "two", "three", "four", "five" };
    Arrays.stream(valueArray).forEach(System.out::println);

Streamオブジェクトに変換して、変換したStreamオブジェクトから
forEachメソッドが使えるようになっています。
出力結果はこうなります。

one
two
three
four
five

Streamオブジェクトに変換しているので、filterも使うことができます。

【まとめ】

Streamインターフェイスにはfilter、collectなどのメソッドがあり、
要素内のオブジェクトに対して操作をすることができました。

List、Set、Map、配列からSteramオブジェクトを
生成する方法についてもCollection#strem、Arrays#streamを
使うと言うことがわかりました。

生成の仕方がわかったので
次からStreamAPIの便利な機能を調べていこうと思います。