参考博文
几个Java 8的例子展示怎样将一个 对象的集合(List)放入一个Map中,并且展示怎样处理多个重复keys的问题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package com.mkyong.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; } }
1. List to Map – Collectors.toMap() 创建一个 Hosting 对象集合, 并且用 Collectors.toMap 去将它转换放入一个 Map.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 package com.mkyong.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) { List<Hosting> list = 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 , "mkyong.com" , 1 )); Map<Integer, String> result1 = list.stream().collect( Collectors.toMap(Hosting::getId, Hosting::getName)); System.out.println("Result 1 : " + result1); Map<String, Long> result2 = list.stream().collect( Collectors.toMap(Hosting::getName, Hosting::getWebsites)); System.out.println("Result 2 : " + result2); Map<Integer, String> result3 = list.stream().collect( Collectors.toMap(x -> x.getId(), x -> x.getName())); System.out.println("Result 3 : " + result3); } }
输出结果
1 2 3 Result 1 : {1=liquidweb.com, 2=linode.com, 3=digitalocean.com, 4=aws.amazon.com, 5=mkyong.com} Result 2 : {liquidweb.com=80000, mkyong.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=mkyong.com}
2. List转Map 重复key问题 以下代码会抛出异常
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 package com.mkyong.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) { List<Hosting> list = 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 , "mkyong.com" , 1 )); list.add(new Hosting(6 , "linode.com" , 100000 )); Map<String, Long> result1 = list.stream().collect( Collectors.toMap(Hosting::getName, Hosting::getWebsites)); System.out.println("Result 1 : " + result1); } }
1 2 3 4 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) //...
为了解决上面重复key的问题,通过增加第三个参数解决:
1 2 3 4 5 Map<String, Long> result1 = list.stream().collect( Collectors.toMap(Hosting::getName, Hosting::getWebsites, (oldValue, newValue) -> oldValue ) );
输出
1 Result 1 : {..., aws.amazon.com=200000, linode.com=90000}
(oldValue, newValue) -> oldValue ==> 如果key是重复的,你选择oldKey or newKey?
如果是用新的值
1 2 3 4 5 Map<String, Long> result1 = list.stream().collect( Collectors.toMap(Hosting::getName, Hosting::getWebsites, (oldValue, newValue) -> newvalue ) );
输出如下
1 Result 1 : {..., aws.amazon.com=200000, linode.com=100000}
3. 排序后转换 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 package com.mkyong.java8; import java.util.*;import java.util.stream.Collectors; public class TestSortCollect { public static void main (String[] args) { List<Hosting> list = 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 , "mkyong.com" , 1 )); list.add(new Hosting(6 , "linode.com" , 100000 )); Map result1 = list.stream() .sorted(Comparator.comparingLong(Hosting::getWebsites).reversed()) .collect( Collectors.toMap( Hosting::getName, Hosting::getWebsites, (oldValue, newValue) -> oldValue, LinkedHashMap::new )); System.out.println("Result 1 : " + result1); } }
1 Result 1 : {aws.amazon.com=200000, digitalocean.com=120000, linode.com=100000, liquidweb.com=80000, mkyong.com=1}
P.S 在上面的例子中, stream 在collect 之前已经被排序, 所以 “linode.com=100000”变为 ‘oldValue’.
References
Java 8 Collectors JavaDoc
Java 8 – How to sort a Map
Java 8 Lambda : Comparator example