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