Stream.collect() の使い方と例を紹介します。
1. Stream.collect()
collect() は、Stream のデータを変形などの処理を行い、必要なデータ型に変換してくれます。
Collectは次の機能を提供します。
- StreamのアイテムをListまたはSetデータ型に変える
- Streamのアイテムをjoinin
- StreamのアイテムをSortingして最大のオブジェクト
- ストリームのアイテムの平均値
このほか、他の多くの機能も提供しています。
Collectの基本的な機能を例と一緒に見てみましょう。
2. StreamのアイテムをHashSetに返す
Stream.collect()
は、Stream の要素を別のデータ型に変換します。
Stream.collect()
は以下のように 3 つの引数を受け取り、これらの引数を利用して Stream の要素を他のデータ型に変換します。
collect(Supplier supplier, BiConsumer accumulator, BiConsumer combiner)
以下の例は Stream.collect()
を使ってストリームの結果を HashSet<String>
で返されるコードです。
HashSet の Supplier、accumulator、combiner を collect() の引数として渡し、 HashSet オブジェクトが返されました。
Stream<String> fruits = Stream.of("banana", "apple", "mango", "kiwi", "peach", "cherry", "lemon");
HashSet<String> fruitHashSet = fruits.collect(HashSet::new, HashSet::add, HashSet::addAll);
for (String s : fruitHashSet) {
System.out.println(s);
}
Output:
banana
apple
cherry
kiwi
lemon
peach
mango
2.1 Collectorsを使用した同じコンテンツの実装
上記のコードは collect に 3 つの params を入れなければならず、やや使いにくいです。 Collectorsというライブラリが基本的な機能を提供し、このような不便さを解決します。
Collectors で collect で HashSet オブジェクトを作成する例を次に示します。引数に Collectors.toSet()
を入れてくれれば Set データ型にしてくれます。
Stream<String> fruits = Stream.of("banana", "apple", "mango", "kiwi", "peach", "cherry", "lemon");
Set<String> fruitSet = fruits.collect(Collectors.toSet());
for (String s : fruitSet) {
System.out.println(s);
}
Output:
banana
apple
cherry
kiwi
lemon
peach
mango
3. Streamの要素をListに変換
Collectors を使用すると、ストリームの要素を List オブジェクトに変換できます。
以下のように Collectors.toList()
を引数に渡すと、List オブジェクトとして返されます。
Stream<String> fruits = Stream.of("banana", "apple", "mango", "kiwi", "peach", "cherry", "lemon");
List<String> fruitList = fruits.collect(Collectors.toList());
for (String s : fruitList) {
System.out.println(s);
}
Output:
banana
apple
mango
kiwi
peach
cherry
lemon
4. Stream要素を1つのStringオブジェクトに変換
Streamのすべての要素を1つのStringにすることもできます。
以下のように Collectors.joining()
を引数として入れてください。
Stream<String> fruits = Stream.of("banana", "apple", "mango", "kiwi", "peach", "cherry", "lemon");
String result2 = fruits.collect(Collectors.joining());
System.out.println(result2);
Output:
bananaapplemangokiwipeachcherrylemon
文字列を合わせるときに区切り文字を入れたい場合は、 Collectors.joining(", ")
のように引数として入れてください。
Stream<String> fruits = Stream.of("banana", "apple", "mango", "kiwi", "peach", "cherry", "lemon");
String result2 = fruits.map(Object::toString).collect(Collectors.joining(", "));
System.out.println(result2);
Output:
banana, apple, mango, kiwi, peach, cherry, lemon
5. 最大のオブジェクトを 1 つだけ返す
ストリームのアイテムを任意の条件で比較して満たされた1つのアイテムだけを返すことができます。
次のコードは、文字列の長さが最も長い要素を返す例です。 Optional<String>
に戻り、文字列の長さを比較する関数(Comparator)は直接作成して引数に渡しました。
import static java.util.Comparator.comparing;
import static java.util.stream.Collectors.maxBy;
Stream<String> fruits = Stream.of("banana", "apple", "mango", "kiwi", "peach", "cherry", "lemon");
Function<String, Integer> getCount = fruit-> fruit.length();
Optional<String> result = fruits.map(Object::toString).collect(maxBy(comparing(getCount)));
System.out.println("result: " + result.orElse("no item"));
Output:
result: banana
6. Collectorsで平均値を取得する
Collectorsは、ストリームアイテムの平均値を取得する機能も提供します。
List<Integer> list = Arrays.asList(1,2,3,4);
Double result = list.stream().collect(Collectors.averagingInt(v -> v*2));
System.out.println("Average: "+result);
Output:
Average: 5.0
7. Custom オブジェクトへの Collect の適用
Custom オブジェクトに対しても Collect を行うこともできます。 Collectors.toMap()
を使うだけです。
Stream<Fruit> fruits2 = Stream.of(new Fruit("1", "banana"), new Fruit("2", "apple"),
new Fruit("3", "mango"), new Fruit("4", "kiwi"),
new Fruit("5", "peach"), new Fruit("6", "cherry"),
new Fruit("7", "lemon"));
Map<String, String> map = fruits2.collect(Collectors.toMap(Fruit::getId, Fruit::getName));
for (String key : map.keySet()) {
System.out.println("key: " + key + ", value: " + map.get(key));
}
static class Fruit {
public String id;
public String name;
Fruit(String id, String name) {
this.id = id;
this.name = name;
}
public String getId() {
return id;
}
public String getName() {
return name;
}
}
Output:
key: 1, value: banana
key: 2, value: apple
key: 3, value: mango
key: 4, value: kiwi
key: 5, value: peach
key: 6, value: cherry
key: 7, value: lemon
8. toMap() 実行時、同じ Key に対する例外処理
toMap() 実行中、同じキーを持っているデータに会うと IllegalStateException を発生させます。
この場合、例外処理を行うことができます。 3番目のparamでは、存在する値と新しい値がどの値を格納するかを定義する必要があります。
以下のコードは、既存の登録値を使用するために (existingValue, newValue) -> existingValue)
として定義しました。
(コードを見るとキー5を持つデータが2つあります。)
Stream<Fruit> fruits2 = Stream.of(new Fruit("1", "banana"), new Fruit("2", "apple"),
new Fruit("3", "mango"), new Fruit("4", "kiwi"),
new Fruit("5", "peach"), new Fruit("6", "cherry"),
new Fruit("5", "lemon"));
Map<String, String> map = fruits2.collect(
Collectors.toMap(item -> item.getId(), item -> item.getName(),
(existingValue, newValue) -> existingValue));
for (String key : map.keySet()) {
System.out.println("key: " + key + ", value: " + map.get(key));
}
キー5の場合、peachとlemonがあり、peachが最初に登録されているので、peachがmapに保存されます。
key: 1, value: banana
key: 2, value: apple
key: 3, value: mango
key: 4, value: kiwi
key: 5, value: peach
key: 6, value: cherry
今回は、同じキーを持つデータがあるときに、2つの値を合計して保存するように定義できます。 3番目のparamで、2つの値を加えた値を返す関数を定義するだけです。
Stream<Fruit> fruits2 = Stream.of(new Fruit("1", "banana"), new Fruit("2", "apple"),
new Fruit("3", "mango"), new Fruit("4", "kiwi"),
new Fruit("5", "peach"), new Fruit("6", "cherry"),
new Fruit("5", "lemon"));
Map<String, String> map = fruits2.collect(
Collectors.toMap(item -> item.getId(), item -> item.getName(),
(existingValue, newValue) -> {
String concat = existingValue + ", " + newValue;
return concat;
}));
for (String key : map.keySet()) {
System.out.println("key: " + key + ", value: " + map.get(key));
}
キー 5 の値を見ると、2 つの文字列を合わせた文字列が保存されました。
key: 1, value: banana
key: 2, value: apple
key: 3, value: mango
key: 4, value: kiwi
key: 5, value: peach, lemon
key: 6, value: cherry
Related Posts
- Java - AtomicReference使用方法
- Java - CountDownLatchを使用する方法、および例
- Java - ScheduledThreadPoolExecutor使用方法
- Java - SummaryStatisticsの使用方法(count、min、max、average)
- Java8 - 関数型インタフェース (Functional Interface) について
- Java - String配列をint配列に変換する
- Java - ArrayList要素の値を変更する方法、replaceAll()
- Java - 2つのリストが同じかどうかを比較
- Java - 配列から特定のIndex要素を削除する3つの方法
- Java - HashMapソート、4つの方法
- Java - 文字列を配列に変換する方法
- Java - ArrayListが空であることを確認する3つの方法
- Java - ArrayListの巡回、4つの方法
- Java - ArrayListの最大値、最小 値を見つける
- Java - ArrayListの合計、平均値の計算
- Java - HashMap巡回、3つの方法
- Java - do whileとwhileの違い
- Java - Lambda式と関数型インタフェース
- Java - List empty(null)チェック、3つの方法
- Java - ArrayListの初期化、4つの方法
- Java - Stream.reduce()の使い方と例
- Java - 2つのマップを結合する(merge、putAll)
- Java - java.util.Dateをjava.sql.Dateに変換する
- Java - ArrayListをStringに変換する
- Java - ClassNotFoundExceptionの発生原因と解決策
- Java - 非静的メソッドは静的コンテキストから参照できません
- Java - NoSuchMethodErrorの原因と解決策
- Java - JSONライブラリを使用する方法(JSONObject、JSONArray)
- Java - byte[]配列をFileに保存
- Java - byte[]の配列をStringに変換
- Java - ファイルのアクセス権を確認し、変更
- Java - 一時フォルダ(Temp directory)パスを取得する
- Javaでシェルスクリプトを実行
- Java - Streamを配列に変換する
- Java - リスト重複排除、2つの方法