目次
個人的によく使う中間操作
Streamで使える中間操作で実務上よく使っている操作について書いてみる。
- map
- reduce
- filter
- sorted
最初理解するまでは時間がかかるけど、うまく使いこなせればコードが短くなって本来やりたいことが見やすくなる。
以下のHogeクラスとList<Hoge>のhogesを使用して説明していきます。
// Lombokを使っている想定
@Data
@AllArgConstractor
class Hoge {
String name;
BigDecimal amount;
int ordinal;
}
List<Hoge> hoges = Arrays.asList(new Hoge[] {
new Hoge("hoge1",new BigDecimal(10), 1)
, new Hoge("hoge2",new BigDecimal(100), 3)
, new Hoge("hoge2",new BigDecimal(1), 2)
});
map
値を別の値に加工できる。
Collection<Hoge>のamountだけを取得したコレクションが欲しい場合とか以下のようにする。
// ①、②ともにSet<BigDecimal> が戻り値となる
// ①メソッド参照
// メソッド参照が使える場面では積極的に使った方が記述が簡潔
hoges.stream().map(Hoge::getAmount)
.collect(Collectors.toSet());
// ②何しているか分かりやすいけど、記述が冗長
hoges.stream().map(hoge -> hoge.getAmount())
.collect(Collectors.toSet());
reduce
業務上だと上記のようなCollection<Hoge>のamountの合計値を出したいとかあるはず。
その場合は「reduce」を合わせて使ってやると合計値が出せる。
// ①簡潔な記述
// reduce最初の引数BigDecimalは初期値
hoges.stream().map(hoge -> hoge.getAmount())
.reduce(BigDecimal.ZERO,BigDecimal::add);
// ②冗長だけどまだわかりやすい
// reduceまでだとOptionalなので、orElseでhogesがOptional.empty()の
// 場合の値を返すようにする。
hoges.stream().map(hoge -> hoge.getAmount())
.reduce((l, r) -> l.add(r))
.orElse(BigDecimal.ZERO);
// ③Collectorsで実現
hoges.stream().map(hoge -> hoge.getAmount())
.collect(Collectors.reducing(BigDecimal.ZERO, BigDecimal::add));
filter
抽出条件に合致するデータだけ対象としたい場合に使用。
for文で頑張る必要がないため、処理が簡潔かつ意図が伝わりやすい記述になる。
条件判定部分が複雑な場合は別メソッドに切り出してやると見やすくなる。
// ① name == "foo"のデータだけ抽出
hoges.stream().filter(hoge -> hoge.getName().equals("foo"))
.collect(Collectors.toList());
sorted
その名の通り、ソートする場合に使用する。
昔のようにComparatorを別で定義せずに使用できるので楽。
// ① ordinal降順にソート
hoges.stream().sorted(Comparator.comparing(Hoge::getOrdinal).reversed())
.collect(Collectors.toList());
※ソート条件となっている項目にnullが含まれている場合にはnullsFirstかnullsLastを使用しないとヌルポで落ちるので注意。
// ② nullを最後にしてordinal降順にソート
hoges.stream().sorted(Comparator.nullsFirst(
Comparator.comparing(Hoge::getOrdinal).reversed()))
.collect(Collectors.toList());
Collectorsなんでもできるな。。。
今度はCollectosでできることでもまとめてみよう。
後半の方コードハイライト効かんなー