13
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Java】 Stream(filter, map, forEach, reduce)

Last updated at Posted at 2020-04-05

概要

「streamで書いて!」と言われてメリットがわからなかったのでまとめる。

わかったこと

  • streamめっちゃ便利。
  • for文やif文のネストが減って見やすい。
  • リストのインスタンス化をしなくてもよくて良い。
  • .addとかも書かなくて良いから、コード量が減って良い。

filter : 条件の絞り込み

List<String> tanakaList = 
    list.stream
        .filter(item -> item.getName.equals("田中"))
        .collect(Collectors.toList());
<解説>
  • 「list」をstreamで分解する。
  • 「item」の中に「list」から要素を一つずつ取得して入れる。
  • filterで名前が"田中"のオブジェクトだけに絞り込む。
  • 分解していたstreamを集めて、collectでリストに変換する。
  • 戻り値「tanakaList」にセットする。
<使って良かったこと>
  • ネストが少ない。
  • リストのインスタンス化を自分で書かなくて良い。
  • セッターを書かなくて良い。

(list.add()で行数取ってたから、なくなってマジで良かった……)

<気になったこと>
  • if-elseのような分岐ができない。もしやりたい場合は、streamを2つ用意して、別の処理として書く必要がある。

  • sqlでソートしてデータ取得などした時にstreamを使うと、stream側でもう一度ソートの処理を書かないといけないので、ソート順を気ににする処理では使わないほうがいいかなと思った。

map:値の変換

List<String> nameList = list.stream
                            .map(item -> item.getName)
                            .collect(Collectors.toList());
<解説>
  • 「list」をstreamで分解する。
  • 「item」の中に「list」から要素を一つずつ取得して入れる。
  • mapで「item」からメソッドを使って名前を取得し「item」の値を加工する。
  • 分解していたstreamを集めて、collectでリストに変換する。
  • 戻り値「nameList」にセットする。
<使って良かったこと>
  • ネストが少ない。
  • リストのインスタンス化を自分で書かなくて良い。
  • セッターを書かなくて良い。
  • メソッドが使えるから、itemに何が入っているのか一目瞭然で良かった。

forEach:ループ処理

    list.stream
        .filter(item -> !item.getName.equals("田中"))
        .forEach({
            item -> throw new Exception(
                "don't tanaka exception."
            )
        });
<解説>
  • 「list」をstreamで分解する。
  • 「item」の中に「list」から要素を一つずつ取得して入れる。
  • filterで名前が"田中ではない"オブジェクトを絞り込む。
  • forEachでループを回して、田中以外のオブジェクトがあった場合「田中じゃないよ」Exceptionをなげる。
<使って良かったこと>
  • ネストが少ない。
  • for(String tanaka : list) すら書かなくて良い。
  • どの場合に何を処理するのかが見やすい。

reduce:要素の集計

    int total = list.stream()
                    .reduce((base, value) -> {
                        return base + value;
                    });

リストの中身

List<int> list = Lists.newArrayList();

        list.add(1);
        list.add(2);
        list.add(3);
<解説>
  • 「list」をstreamで分解する。
  • 「base」の中に「list」から要素を一つずつ取得して「最初の要素」を入れる。
  • 「value」の中に「list」から要素を一つずつ取得して「次の要素」を入れる。
  • 1回目にreduceが実行されるとき、base=1、value=2で実行される。
  • 2回目はbase=2、value=3で実行される。
  • 全て足したものをreturnし戻り値にセットする。

わからなかったこと

1:なぜ「item.getName」のようにメソッドが使えるのか。
  -> 名前をSQLから取得したmodelクラス「Student」がある。
    listを「List list」で定義すると、
    Streamでlistを分解してitemに入れていることから、
    itemの型は「Student」であることがわかる。
    だから、Studentクラスに存在するメソッドが使える!!
    getNameメソッドはStringを返すから、戻り値も問題ない。

Studentクラス

@Data
@Builder
class Student {
    private String name;
}

Stream.java

  List<Student> list = Lists.newArrayList();

  List<String> tanakaList = list.stream
                                .map(item -> item.getName.equals())
                                .collect(Collectors.toList())

まとめ

ラムダも使い慣れていなかったし、streamって何やねん状態だったけど、使ってみたら圧倒的にコード量が減ったから良かった。一番のメリットはネストの深さが一気に解消されたこと。こんな便利なの知ってしまったら、今後取り憑かれたように使っちゃうなと思った。だから、自分がまだ知らないデメリットとかあったら怖いなと思った。(でも、しばらくは使い倒すと思う、先輩教えてくれてありがとう……)

13
12
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?