JavaのStreamAPIについて理解する

# StreamAPIについて
StreamAPIはコレクションの操作を読み易くするために導入された機能となります。
今回はStreamAPIの利用法について説明します。
StreamAPIを利用するこで直感的にコードが見やすくなると思います。

# StreamAPIの使い方について
StremaAPIのシンプルな利用方法と少し複雑な利用方法について紹介しようと思います。
シンプルな利用方法はわかりやすいですが、少し複雑な利用方法についてはデータを結合したい場合のケースを想定した使い方を紹介します。

## シンプルなリストデータ（M件）を扱う場合
特定の条件に合致したデータを抽出する場合のコードについて説明します。

personリストから特定の文字列を抽出する場合は以下のようになります。StreamAPIを使用した場合はif文を使用せず、シンプルなコードになります。

### PersonとAddressクラスの定義

#### Personクラス
```java
class Person {
    private int personId;
    private String name;

    public Person(int personId, String name) {
        this.personId = personId;
        this.name = name;
    }

    public int getPersonId() {
        return personId;
    }

    public String getName() {
        return name;
    }
}
```

#### Addressクラス
```java
class Address {
    private int personId;
    private String city;

    public Address(int personId, String city) {
        this.personId = personId;
        this.city = city;
    }

    public int getPersonId() {
        return personId;
    }

    public String getCity() {
        return city;
    }
}

```

### for文を用いた単純な抽出
```java
    public static void main(String[] args) {

        List<Person> persons = Arrays.asList(
                new Person(1, "Suzuki"),
                new Person(2, "Tanaka"),
                new Person(3, "Sato"));

        for (Person person : persons) {
            if (person.getName().equals("Suzuki")) {
                System.out.println(person.getName());
            }
        }
    }
```

### StreamAPIのfilterを用いて抽出
for文、if文がないため、見た目がシンプル
```java
    public static void main(String[] args) {

        List<Person> persons = Arrays.asList(
                new Person(1, "Suzuki"),
                new Person(2, "Tanaka"),
                new Person(3, "Sato"));

        persons.stream()
            .filter(p -> p.getName().equals("Suzuki"))
            .forEach(p -> System.out.println(p.getName()));
    }

```

## ちょっと複雑なリストデータ（M×N）件を扱う場合
personデータをaddressデータを用意し、personIdで結合したい場合もStreamAPIで表現可能となります。

### for文を用いたデータ結合方法
```java
    public static void main(String[] args) {

        List<Person> persons = Arrays.asList(
                new Person(1, "Suzuki"),
                new Person(2, "Tanaka"),
                new Person(3, "Sato"));

        List<Address> addresses = Arrays.asList(
                new Address(1, "Hokkaido"),
                new Address(2, "Aomori"),
                new Address(3, "Iwate"),
                new Address(4, "Miyagi"));

        for (Person person : persons) {
            for (Address address : addresses) {
                if (address.getPersonId() == person.getPersonId()) {
                    System.out.println(person.getName() + ":" + address.getCity());
                }
            }
        }

// 出力結果
Suzuki:Hokkaido
Tanaka:Aomori
Sato:Iwate
```

### StreamAPIを用いて結合する場合
1. personsのpersonIdとaddressesのpersonIdが同値のpersonsデータを抽出
1. 抽出したpersonsデータのpersonIdと同値のaddressesを結合(collect箇所）
```java
    public static void main(String[] args) {

        List<Person> persons = Arrays.asList(
                new Person(1, "Suzuki"),
                new Person(2, "Tanaka"),
                new Person(3, "Sato"));

        List<Address> addresses = Arrays.asList(
                new Address(1, "Hokkaido"),
                new Address(2, "Aomori"),
                new Address(3, "Iwate"),
                new Address(4, "Miyagi"));

        persons.stream()
                .filter(person -> addresses.stream().anyMatch(address -> address.getPersonId() == person.getPersonId()))
                .collect(Collectors.toMap(Person::getName,
                        person -> addresses.stream()
                                .filter(address -> address.getPersonId() == person.getPersonId()).findFirst()
                                .map(address -> address).orElse(null)))
                .forEach((name, address) -> System.out
                        .println(address.getPersonId() + ":" + name + ":" + address.getCity()));
    }

```

# 終わりに
StreamAPIを使用した、シンプルな使い方、データを結合する方法について解説しました。
データ結合については複雑な処理になるため慣れが必要となります。
SteamAPIで用意されているメソッドは種類が豊富なため、実際にコードを書いて動かすことで腹落ちするかと思いますので、たくさんコードを書いてマスターしていきましょう。