5分で分るJava Stream API

この記事ではJava Stream APIが読めない人を対象にしています。

以下の人にオススメです

- Javaとか昔は書いてたけど最近は書いてない
- Stream APIが読めなくてコーディングを辞めた
- とにかく時間がないから勘所だけ知りたい

## 最初に
Java Stream APIとは、 InputStreamや、OutputStreamなどのI/Oクラスとは関係ありません。
List,SetなどのCollection Object,または配列などのループ可能な要素をループの中で一度だけ処理する仕組みの事を言います。
※Streamは一度処理すると再利用できません。ただし、Streamはchain(連鎖)させることで複数の処理が可能です。

## Stream APIを利用して行うものは、よく使うのは以下の2点です
- エンティティを変換する(mapメソッド)
- コレクションをフィルターする(filterメソッド)

Javaのコードを記載します。

``` java
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class StreamTest {
    public static void main(String[] args) {
        List<String> csvList = new ArrayList<>();
        csvList.add("田中 直樹,MAN");
        csvList.add("北村 一輝,MAN");
        csvList.add("加藤 しずか,WOMAN");
        csvList.add("小野 妹子,UNKNOWN");
        // １.エンティティを変換する。(map)
        List<Person> persons = csvList.stream().map(Person::convertPersonFromCSV).collect(Collectors.toList());

        // 2.エンティティをフィルターする。(filter)
        List<Person> mens = persons.stream().filter(p -> p.getGender() == Gender.MAN).collect(Collectors.toList());

        System.out.println("Print all persons");
        persons.forEach(System.out::println);

        System.out.println("Print mens only");
        mens.forEach(p -> System.out.println(p.getName()));
    }

    enum Gender {
        MAN,
        WOMAN,
        UNKNOWN;
    }

    static class Person {
        private String name;
        private Gender gender;

        public Person(String name, Gender gender) {
            this.name = name;
            this.gender = gender;
        }

        @Override
        public String toString() {
            return String.format("My name is %s . \r\nMy gender is %s.", name, gender);
        }

        public String getName() {
            return this.name;
        }

        public Gender getGender() {
            return this.gender;
        }

        public static Person convertPersonFromCSV(String csv) {
            String[] csvStrings = csv.split(",");
            if (csvStrings.length != 2) throw new IllegalArgumentException("csv is illegal format.");
            return new Person(csvStrings[0], Gender.valueOf(csvStrings[1]));
        }
    }
}
```

それでは、順番に上記を見ていきましょう
### エンティティを変換する
エンティティを変換する際は、mapメソッドを使用します。
<b>mapメソッドで変換、collectメソッドでStreamを再度Collection型に変換します。</b>

主に以下の3種類の書き方が出来ます。

``` java
csvList.stream().map(Person::convertPersonFromCSV).collect(Collectors.toList());
csvList.stream().map(csv -> Person.convertPersonFromCSV(csv)).collect(Collectors.toList());
csvList.stream().map(csv -> {
                         Person person = Person.convertPersonFromCSV(csv);
                         return person;
                     }).collect(Collectors.toList());
``` 

どれもやっていることは同じで、csvListの要素であるStringを取得して、
Personオブジェクトに変換して返却するメソッドを実行しています。

- 1番目は引数のcsvを省略する書き方
- 2番目はreturnメソッドを省略して1行で記述する書き方
- 3番目は何も省略しない書き方

<b>Streamを使うことで、List<String>を1行(ワンライナー)でList<Person>に変換することが出来ました。</b>
Streamを使用することのメリットの一つとして、コードの記述量を減らすことが出来るというものがあります。

### 以下は時間のない人は飛ばしてください。
- csvList.stream()
  - Streamオブジェクトを取得します。
- map(Person::convertPersonFromCSV)
  - mapメソッドの引数として、csvListのGenericインターフェースであるStringが与えられます。
  - Personクラスのエンティティ変換メソッドを呼び出しentityの変換を行い、entityクラスを返却します。
  - Functionインターフェースを実装したメソッドを使用して、StringクラスをPersonクラスに変換して返却しています。
- collect(Collectors.toList())
  - 変換されたPersonを集めます。
  - Collectors.toList()でListクラスに追加していきます。
  - Collectors.toXXX()でSetやMapにも変換できます。toMapの場合、keyとvalueを返却する2つのFunctionを記述する必要があります。
- メソッドの処理の順序としては、「mapで変換,collectでStreamで処理したオブジェクトをリストに格納」という処理を繰り返すイメージとなります。

### コレクションをフィルターする
<b>コレクションから特定の要素を除外して、新しいコレクションオブジェクトを作成することが出来ます。</b>
filterメソッドを使用して、残したい対象のオブジェクトを記載します。

``` java
persons.stream().filter(p -> p.getGender() == Gender.MAN).collect(Collectors.toList());
```

<b>Streamを使うことで、List<Person>から男性のみを抽出した新しいコレクションをワンライナーで作成できました。</b>

- filter(p -> p.getGender() == Gender.MAN)
  - Personを引数に取り、booleanを返却します。


## Stream APIを使用してよくやる他のこと
- findAny
  - filterと組み合わせて、特定の要素が存在するかどうかを検出する。
- sum
  - mapToIntと組み合わせて、コレクションの合計数を算出する。
- reduce
  - コレクションの要素を結合して一つのオブジェクトに纏める。