「 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       ));
7}

要素の値を合計する

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

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を扱う新たな方法
ttp://www.javazuki.com/articles/javase/javase8-tutorial02.html
現在は閉鎖