「Javaを書いているけれどもJava屋とは言えない」私がよく使うStream APIの備忘録です。

Web系の実装で「DAOからSELECTしたリストを操作する」感じの処理が中心ですよ。

前提

テーブルをマッピングするValueObjectを用意します。

TCard.java

1@Data
2class TCard implements Serializable {
3    private Integer userId;
4    private Integer id;
5    private Integer cardId;
6    private Integer level;
7    private Boolean isDeleted;
8    :
9}

所持カードを管理テーブルのイメージです。
メンバは、所有者であるユーザID、カードを識別するための連番、マスタIDなど。

変換

IDのリストを作る

WHERE INに与えるIDをまとめる場合など、よく使います。

1public List<Integer> toIdList(List<TCard> cards) {
2    return cards().stream()
3        .map(e -> e.getId())
4        .collect(Collectors.toList());
5}

文字列として受け取ったリストをIntegerに変換する

HTML Formから受け取った文字列のリストを型変換するイメージです。

1public List<Integer> toIntegerList(List<String> list) {
2    return list.stream()
3        .map(s -> NumberUtils.toInt(s))
4      .collect(Collectors.toList());
5}

IDがキーのHashMapをつくる

Listからハッシュマップに変換します。
複数データの突合を行うような場合に重宝します。

1public Map<Integer, TCard> toHashMap(List<TCard> cards) {
2    return cards.stream()
3        .collect(Collectors.toMap(
4            e -> e.getId(),
5            e -> e
6        ));
7}

マッチ・検索

要素を1つ求める

1public TCard findOne(List<TCard> cards, Integer searchId) {
2    return cards.stream()
3        .filter(s -> s.getId().equals(searchId))
4        .findFirst()
5        .get();
6}

.findFirst().findAny()の違いがよくわかりません。。。

.findFirst()はOptionalが返ります。
上記のようにそのまま.get()するとNullPointerExceptionがスローされますのでダメですよ。

マッチする要素があるか調べる

1public Boolean hasAny(List<TCard> cards, List<Integer> searchIdList) {
2    return cards.stream()
3        .anyMatch(s -> searchIdList.contains(s.getId()));
4}

allMatch()もあり。

重複がないか調べる

「カードがすでに他のデッキにセットされているかどうか」のような処理で使います。

1public Boolean hasNothing(List<TCard> cards, List<Integer> searchIdList) {
2    return cards.stream()
3        .noneMatch(s -> searchIdList.contains(s.getId()));
4}

集計

ID別にカウント数る

所持カードから同じものをID別でカウントするイメージです。

1public Map<Integer, Long> countById(List<TCard> cards) {
2    return  cards.stream()
3       .collect(Collectors.groupingBy(
4            e -> e.getCardId(),
5            Collectors.counting()
6       ));

要素の値を合計する

リスト内の指定要素を合計します。
サンプルが強引なのはご容赦ください。。。

1public Integer sum(List<TCard> cards) {
2    return cards.stream()
3        .mapToInt(s -> s.getLevel())
4        .sum();
5}

最大値を得る

1public Integer getMaxLv(List<TCard> cards) {
2    return cards.stream()
3        .max( (l, r) -> Integer.compare(l.getLevel(), r.getLevel()) )
4        .orElse(0);
5}

終わりに

forEach()concat()など、他にも使いやすい機能がたくさんありますね。

誤りや、もっとシンプルな方法がありましたらぜひ教えてください。


参考

Java 8 Stream API にテキストを流してみた(終端操作編)
http://qiita.com/kumazo@github/items/284098c530fceb05805c

Java8 逆引き Stream API
http://qiita.com/nesheep5/items/da42df92397285d4ad0f

Java好き - Optional - nullを扱う新たな方法
http:// www.javazuki.com/articles/javase/javase8-tutorial02.html
現在は閉鎖

Javaによる関数型プログラミング ―Java 8ラムダ式とStream

Venkat Subramaniam
出版社:オライリージャパン  発売日:2014-10-24

Amazonで詳細を見る

Javaパフォーマンス

Scott Oaks
出版社:オライリージャパン  発売日:2015-04-11

Amazonで詳細を見る

Javaエンジニア養成読本 [現場で役立つ最新知識、満載!] (Software Design plus)

きしだ なおき,のざき ひろふみ,吉田 真也,菊田 洋一,渡辺 修司,伊賀 敏樹
出版社:技術評論社  発売日:2014-11-11

Amazonで詳細を見る