Java 8 –リストをマップに変換
オブジェクトのList
をMap
に変換する方法、および重複したキーを処理する方法を示すJava8の例はほとんどありません。
Hosting.java
package com.example.java8 public class Hosting { private int Id; private String name; private long websites; public Hosting(int id, String name, long websites) { Id = id; this.name = name; this.websites = websites; } //getters, setters and toString() }
1. マップリスト– Collectors.toMap()
Hosting
オブジェクトのリストを作成し、Collectors.toMap
を使用してそれをマップに変換します。
TestListMap.java
package com.example.java8 import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.stream.Collectors; public class TestListMap { public static void main(String[] args) { Listlist = new ArrayList<>(); list.add(new Hosting(1, "liquidweb.com", 80000)); list.add(new Hosting(2, "linode.com", 90000)); list.add(new Hosting(3, "digitalocean.com", 120000)); list.add(new Hosting(4, "aws.amazon.com", 200000)); list.add(new Hosting(5, "example.com", 1)); // key = id, value - websites Map result1 = list.stream().collect( Collectors.toMap(Hosting::getId, Hosting::getName)); System.out.println("Result 1 : " + result1); // key = name, value - websites Map result2 = list.stream().collect( Collectors.toMap(Hosting::getName, Hosting::getWebsites)); System.out.println("Result 2 : " + result2); // Same with result1, just different syntax // key = id, value = name Map result3 = list.stream().collect( Collectors.toMap(x -> x.getId(), x -> x.getName())); System.out.println("Result 3 : " + result3); } }
出力
Result 1 : {1=liquidweb.com, 2=linode.com, 3=digitalocean.com, 4=aws.amazon.com, 5=example.com} Result 2 : {liquidweb.com=80000, example.com=1, digitalocean.com=120000, aws.amazon.com=200000, linode.com=90000} Result 3 : {1=liquidweb.com, 2=linode.com, 3=digitalocean.com, 4=aws.amazon.com, 5=example.com}
2. マップリスト-重複キー!
2.1 Run below code, and duplicated key errors will be thrown!
TestDuplicatedKey.java
package com.example.java8; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.stream.Collectors; public class TestDuplicatedKey { public static void main(String[] args) { Listlist = new ArrayList<>(); list.add(new Hosting(1, "liquidweb.com", 80000)); list.add(new Hosting(2, "linode.com", 90000)); list.add(new Hosting(3, "digitalocean.com", 120000)); list.add(new Hosting(4, "aws.amazon.com", 200000)); list.add(new Hosting(5, "example.com", 1)); list.add(new Hosting(6, "linode.com", 100000)); // new line // key = name, value - websites , but the key 'linode' is duplicated!? Map result1 = list.stream().collect( Collectors.toMap(Hosting::getName, Hosting::getWebsites)); System.out.println("Result 1 : " + result1); } }
出力-以下のエラーメッセージは少し誤解を招く可能性があり、キーの値の代わりに「linode」を表示する必要があります。
Exception in thread "main" java.lang.IllegalStateException: Duplicate key 90000 at java.util.stream.Collectors.lambda$throwingMerger$0(Collectors.java:133) at java.util.HashMap.merge(HashMap.java:1245) //...
2.2 To solve the duplicated key issue above, pass in the third mergeFunction argument like this :
Mapresult1 = list.stream().collect( Collectors.toMap(Hosting::getName, Hosting::getWebsites, (oldValue, newValue) -> oldValue ) );
出力
Result 1 : {..., aws.amazon.com=200000, linode.com=90000}
Note(oldValue, newValue) -> oldValue
=⇒キーが重複している場合、oldKeyとnewKeyのどちらを使用しますか?
3.3 Try newValue
Mapresult1 = list.stream().collect( Collectors.toMap(Hosting::getName, Hosting::getWebsites, (oldValue, newValue) -> newvalue ) );
出力
Result 1 : {..., aws.amazon.com=200000, linode.com=100000}
3. リストからマップ–並べ替えと収集
TestSortCollect.java
package com.example.java8; import java.util.*; import java.util.stream.Collectors; public class TestSortCollect { public static void main(String[] args) { Listlist = new ArrayList<>(); list.add(new Hosting(1, "liquidweb.com", 80000)); list.add(new Hosting(2, "linode.com", 90000)); list.add(new Hosting(3, "digitalocean.com", 120000)); list.add(new Hosting(4, "aws.amazon.com", 200000)); list.add(new Hosting(5, "example.com", 1)); list.add(new Hosting(6, "linode.com", 100000)); //example 1 Map result1 = list.stream() .sorted(Comparator.comparingLong(Hosting::getWebsites).reversed()) .collect( Collectors.toMap( Hosting::getName, Hosting::getWebsites, // key = name, value = websites (oldValue, newValue) -> oldValue, // if same key, take the old key LinkedHashMap::new // returns a LinkedHashMap, keep order )); System.out.println("Result 1 : " + result1); } }
出力
Result 1 : {aws.amazon.com=200000, digitalocean.com=120000, linode.com=100000, liquidweb.com=80000, example.com=1}
P.S In above example, the stream is sorted before collect, so the “linode.com=100000” became the ‘oldValue’.