概要
ListをStreamで処理する方法のうち、よく使う処理方法を掲載します。
前準備
プリミティブなListでStreamを利用するシーンをあまり想定できなかったので、オブジェクトのListでの事例と致します。
まずは以下のProductクラスがあると仮定します。
Productクラス
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
public class Product { private String _category; private String _name; private int _price; public Product(String category, String name, int price){ _category = category; _name = name; _price = price; } public String category() { return _category; } public String name() { return _name; } public int price() { return _price; } } |
実装例
テストがGreeanになったコードで記載いたします。
特定の要素のみを取得する
Listの中から特定の条件に該当する要素だけを取得したい場合、filterを使います。
ここでは、カテゴリー:玩具に該当するProductオブジェクトのみを取得しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
@Test void List_特定の要素のみを取得する() { List<Product> products = new ArrayList<>() { { add(new Product("衣類", "靴下", 200)); add(new Product("食品", "ふりかけ", 100)); add(new Product("玩具", "プラモデル", 1000)); } }; List<Product> toys= products.stream() .filter(product -> "玩具".equals(product.category())) .collect(Collectors.toList()); assertThat(toys.get(0).name(), is("プラモデル")); } |
合計を算出する
Productオブジェクトのpriceを合計した結果を取得します。
通常のmapではなく、mapToIntを使うことでIntStreamを返すことができます。
IntStreamにはsumメソッドが用意されており、それにより合計を算出することができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
@Test void List_合計を算出する() { List<Product> products = new ArrayList<>() { { add(new Product("衣類", "靴下", 200)); add(new Product("食品", "ふりかけ", 100)); add(new Product("玩具", "プラモデル", 1000)); } }; int sumAmount = products.stream() .mapToInt(product -> product.price()) .sum(); assertThat(sumAmount, is(1300)); } |
最初の要素を取得する
Streamで最初の要素を取得する場合、findFirstを使います。
でも、Listの最初の要素を取得するには、「List.get(0)で十分ではないか?」と思われたのではないでしょうか?
その場合、もし要素が無ければIndexOutOfBoundsExceptionが発生します。
findFristの場合はOptionalを返してくれるので、orElseなどで要素が無い場合の戻り値を決めてあげることができるのがメリットです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
@Test void List_最初の要素を取得する() { List<Product> products = new ArrayList<>() { { add(new Product("衣類", "靴下", 200)); add(new Product("食品", "ふりかけ", 100)); add(new Product("玩具", "プラモデル", 1000)); } }; Product first = products.stream() .findFirst() .orElse(null); assertThat(first.name(), is("靴下")); } |
最後の要素を取得する
lastのような機能は無いので、reduceを使用して最後の要素を取得する方法があります。
reduceの演算結果として、常にCurrentの要素が返ってくるようにすることで、最後の要素が取得できます。
Listの要素が無い場合のために、orElseで戻り値を定義しておくこともできます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
@Test void List_最後の要素を取得する() { List<Product> products = new ArrayList<>() { { add(new Product("衣類", "靴下", 200)); add(new Product("食品", "ふりかけ", 100)); add(new Product("玩具", "プラモデル", 1000)); } }; Product last = products.stream() .reduce((acc, current) -> current) .orElse(null); assertThat(last.name(), is("プラモデル")); } |
なんらかの値に変換した値を取得する
mapを使用して、何らかの加工を施した結果を取得する方法です。
ここではオブジェクトの各フィールド値を文字列型にフォーマットして返しているだけです。
(正直これであれば、Productクラスにtextメソッドのようなものを作ってしまった方が適切ですが、mapの事例として記載させて頂きました)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
@Test void List_なんらかの値に変換した値を取得する() { List<Product> products = new ArrayList<>() { { add(new Product("衣類", "靴下", 200)); add(new Product("食品", "ふりかけ", 100)); add(new Product("玩具", "プラモデル", 1000)); } }; List<String> formatedList = products.stream() .map(product -> new Formatter(). format("[%s, %s, %d]", product.category(), product.name(), product.price()) .toString()) .collect(Collectors.toList()); assertThat(formatedList.get(2).toString(), is("[玩具, プラモデル, 1000]")); } |
並べ替えた結果を取得する(昇順)
price順で並び替えた結果を取得しています。
comparingメソッドの引数に、比較用のソート・キーを指定します。
そうするとComparatorを返してくれます。
そのComparatorはcompareで大小比較するので、小さい順に並んだ結果が返ってきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
@Test void List_並べ替えた結果を取得する_昇順() { List<Product> products = new ArrayList<>() { { add(new Product("衣類", "靴下", 200)); add(new Product("食品", "ふりかけ", 100)); add(new Product("玩具", "プラモデル", 1000)); } }; List<Product> ascOrderOfPrice = products.stream() .sorted(Comparator.comparing(Product::price)) .collect(Collectors.toList()); assertThat(ascOrderOfPrice.get(0).name(), is("ふりかけ")); } |
並べ替えた結果を取得する(降順)
昇順にreversedメソッドを付けることで降順にしています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
@Test void List_並べ替えた結果を取得する_降順() { List<Product> products = new ArrayList<>() { { add(new Product("衣類", "靴下", 200)); add(new Product("食品", "ふりかけ", 100)); add(new Product("玩具", "プラモデル", 1000)); } }; List<Product> ascOrderOfPrice = products.stream() .sorted(Comparator.comparing(Product::price).reversed()) .collect(Collectors.toList()); assertThat(ascOrderOfPrice.get(0).name(), is("プラモデル")); } |
まとめ
- 特定の要素を取得するときはfilterを使う。
- 合計を算出する場合、mapToIntでIntStreamにしてからsumで取得する。
- 最初の要素はfindFistを使う。
- 最後の要素はreduceで現在の要素を常に返すことで取得する。
- 何らかの値に変換したい場合はmapを使う。
- 並び替えはsortedとComparatorを組み合わせる。
- 降順はreversedを使う。
最後に
ListはJava Silver SE 11の出題範囲になっています。
ぜひしっかりと理解して合格を目指しましょう!
コメント