【Java】躓いたStreamを備忘程度に

## はじめに
`Stream API`について、超正確に理解したい方は、[Oracle](https://docs.oracle.com/javase/jp/8/docs/api/java/util/stream/Stream.html)のドキュメントを読んでいただければと思います。
当記事はあくまでほぼ開発未経験だったエンジニアのざっくり理解を自分の備忘と読者の皆さんへ展開することを目的としています。

## Stream APIとは
Stream APIとはJava8から追加された、コレクションに対して以前までfor文で書いていた繰り返し処理を簡単？に記述することができる機能です。（もっと深いものですが、ざっくり理解ということで。。。）
Streamを理解する上で以下のポイントだけおさえれば、なんとかなります、きっと。

**ポイント**
1. あるコレクションからStreamを生成（今回はstream()を使用）
1. 中間操作でStream内の要素に対して操作を実施（今回はfilter()メソッドを使用）
1. 終端操作でStreamに対して処理を実施（今回はcollect()を使用collect）

以上三点です。非常に簡単ですね。
今回は私が幾度か目にしたメソッドを取り上げますが、生成、中間操作、終端操作には様々なメソッドが用意されているので、本記事が調べるきっかけになっていただけると幸いです。

## 実装例
説明は以上なので、ここからは簡単な実装例を交えてStreamを紹介していきます。
例として挙げる題材は以下とします。
> NumberDtoのリストから偶数フラグがtrueの要素だけ取得し、偶数リストを作成する。
```java:NumberDto.java
public class NumberDto {
  /**
   * 数字.
   */
  int number;

  /**
   * 偶数か否か.
   */
  boolean isEven;
}
```
### for文を使用した場合
それではまずfor文を使った場合のコードを見てみたいと思います。
```java:for文
public class NumberService{
    public void pickUpEvenNumber() {
        // 前準備.
        List<NumberDto> numberDtoList = new ArrayList<>();
        NumberDto numberDto1 = new NumberDto();
        numberDto1.setNumber(1);
        numberDto1.setEven(false);
        numberDtoList.add(numberDto1);
                   .
                 (省略)
                   .
        NumberDto numberDto10 = new NumberDto();
        numberDto10.setNumber(10);
        numberDto10.setEven(true);
        numberDtoList.add(numberDto10);

        // 偶数フラグがtrueのリストを作成する.
        List<NumberDto> evenNumberDtoList = new ArrayList<>();
        for (NumberDto numberDto : numberDtoList) {
            if (numberDto.isEven()) {
                evenNumberDtoList.add(numberDto);
            }
        }
    }
}
```
こんな感じですかね。これぐらいならfor文で良い感は否めませんが、例なので許してください。
あと、偶数か否かのboolean変数なんか持たせず、
if文の条件を`numberDto.getNumber() % 2 == 0`でいいやん！のコメントだけは受け付けません！
(いい例が思いつきませんでした、すみません。。。)

### Stream APIを使用した場合
次にStream APIを使った場合のコードを見てみたいと思います。
```java:for文
public class NumberService{
    public void pickUpEvenNumber() {
        // 前準備.
        List<NumberDto> numberDtoList = new ArrayList<>();
        NumberDto numberDto1 = new NumberDto();
        numberDto1.setNumber(1);
        numberDto1.setEven(false);
        numberDtoList.add(numberDto1);
                   .
                 (省略)
                   .
        NumberDto numberDto10 = new NumberDto();
        numberDto10.setNumber(10);
        numberDto10.setEven(true);
        numberDtoList.add(numberDto10);

        // 偶数フラグがtrueのリストを作成する.
        List<NumberDto> evenNumberDtoList =
            numberDtoList.stream().filter(NumberDto::isEven).collect(Collectors.toList());
    }
}
```
Stream APIを使用することで、for文を使用した場合には6行かかっていた処理が、1行で書くことが可能となります。
filter()メソッドの引数で`NumberDto::isEven`と記載していますが、これは`メソッド参照`と呼ばれるものです。
メソッド参照に辿り着くまでにも苦労したのをよく覚えています。
同じ箇所で躓く方が少しで減ることを願って、`// 偶数フラグがtrueのリストを作成する.`の部分をラムダ式で記述すると以下になります。
```java:ラムダ式
// 偶数フラグがtrueのリストを作成する.
List<NumberDto> evenNumberDtoList =
    numberDtoList.stream().filter(n -> n.isEven()).collect(Collectors.toList());
```

## おわりに
私が最初Streamの壁にぶち当たった時、前提のラムダ式も全くわからず、理解まですごく時間がかかりました。
上記記載の[ポイント](https://qiita.com/__y_on/items/cfedc1ba4fed040a1251#:~:text=%E3%81%AA%E3%82%8A%E3%81%BE%E3%81%99%E3%80%81%E3%81%8D%E3%81%A3%E3%81%A8%E3%80%82-,%E3%83%9D%E3%82%A4%E3%83%B3%E3%83%88,-%E3%81%82%E3%82%8B%E3%82%B3%E3%83%AC%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%8B%E3%82%89)、`ラムダ式`、`メソッド参照`を頭に入れた上で、より深く潜っていくと少しは理解にかかる時間が短縮できるかと思います。
本記事が読者の方々のお力に少しでもなれると幸いです。