public static <T,K,U> Collector<T,?,Map<K,U>> toMap(Function<? super T,? extends K> keyMapper, Function<? super T,? extends U> valueMapper)
简单理解就是把元素放到map中保存,map中的key和value都是根据元素计算而来。
先看两个官方的例子:
Map<Student, Double> studentToGPA
= students.stream().collect(
toMap(Function.identity(),
student -> computeGPA(student)));
这个例子作用很明显,就是把student集合中的每个student放到map中保存,key取student这个对象本身,value通过computeGPA这个方法对student进行计算得出。
再看一个例子:
Map<String, Student> studentIdToStudent
= students.stream().collect(
toMap(Student::getId,
Function.identity()));
作用和上面一样,key取值student对象中的id,value取student这个对象本身。
再看两个例子:
void test31() {
List<User> userList = List.of((new User("mail1","adr1")),(new User("mail2","a2")),(new User("mail3","adr3")));
Map<User, String> map = userList.stream().collect(Collectors.toMap(a -> a, b -> b.getAddr()));
map.forEach((k,v) -> System.out.println(k.toString()+ ":"+ v));
}
运行结果:
com.azhu.java8.optionalStudy.User@769c9116:a2
com.azhu.java8.optionalStudy.User@6aceb1a5:adr3
com.azhu.java8.optionalStudy.User@6956de9:adr1
假设有个需求,需要把User类型的集合中的所有User取其mail为key,addr为value保存在map中返回。
void test31() {
List<User> userList = List.of((new User("mail1","adr1")),(new User("mail2","a2")),(new User("mail3","adr3")));
Map<String, String> map = userList.stream().collect(Collectors.toMap(a -> a.getEmail(), b -> b.getAddr()));
map.forEach((k,v) -> System.out.println(k+ ":"+ v));
}
运行结果:
mail3:adr3
mail2:a2
mail1:adr1
public static <T,K,U> Collector<T,?,Map<K,U>> toMap(Function<? super T,? extends K> keyMapper, Function<? super T,? extends U> valueMapper, BinaryOperator<U> mergeFunction)
相比上一个函数多了一个参数,mergeFunction根据其含义就能理解这就是一个数据合并的方法。其作用就是当集合元素中根据key计算方法得出了相同的Key值就根据mergeFunction方法对这两个key值相同的元素进行处理得到一个value。
在上面那个方法中如果存在同样的key就会抛出异常。看个例子:
void test32() {
List<User> userList = List.of((new User("mail1","adr1")),(new User("mail2","a2")),(new User("mail1","adr3")));
Map<String, String> map = userList.stream().collect(Collectors.toMap(a -> a.getEmail(), b -> b.getAddr(), (c,d) -> c+" - "+d));
map.forEach((k,v) -> System.out.println(k+ ":"+ v));
}
以上例子中存在两个mail1,因此如果用第一个toMap方法处理就会报异常,在这里我们添加了一个出现重复key这种情况的处理方法,我们把所有重复key的value通过“-”符号连接起来形成一个key value键值对。上面代码执行结果如下:
mail2:a2
mail1:adr1 - adr3
这里再说一下mergeFunction函数处理流程,入参是两个,代码中定义的是c,d;执行流程是第一次遇到重复key的时候把第一个把key对应的value赋值给c,把第二个key对应的value赋值给d,然后这两个重复key保留一个,把这两个value用“-”连接起来当作其对应的value然后继续执行,当再次遇到相同key的时候再重复上面的步骤。上面例子如果还有一个user(“mail1”,”adr4”),那运行结果就是:mail1:adr1 - adr3 – adr4
public static <T,K,U,M extends Map<K,U>> Collector<T,?,M> toMap(Function<? super T,? extends K> keyMapper, Function<? super T,? extends U> valueMapper, BinaryOperator<U> mergeFunction, Supplier<M> mapFactory)
这个方法又多了一个参数,根据参数字面意思也能理解这个参数是用来定义最终返回的数据类型的,上面的方法默认返回的是HashMap类型,如果我们不想要这个类型就可以添加这个参数来自定义返回的数据类型。
参数定义:Supplier<M> mapFactory 这个函数参数传递数据类型是M,再看看返回数据类型的定义:M extends Map<K,U> 因此自定义的数据类型只能是实现Map接口的数据类型。
看个例子:
void test33() {
List<User> userList = List.of((new User("mail1","adr1")),(new User("mail2","a2")),(new User("mail1","adr3")),(new User("mail1","adr4")));
Map<String, String> map = userList.stream().collect(Collectors.toMap(a -> a.getEmail(), b -> b.getAddr(), (c,d) -> c+" - "+d));
map.forEach((k,v) -> System.out.println(k+ ":"+ v));
System.out.println(map.getClass().getTypeName());
Map<String, String> map2 = userList.stream().collect(Collectors.toMap(a -> a.getEmail(), b -> b.getAddr(), (c,d) -> (c+" - "+d), TreeMap::new));
map2.forEach((k,v) -> System.out.println(k+ ":"+ v));
System.out.println(map2.getClass().getTypeName());
}
执行结果:
mail2:a2
mail1:adr1 - adr3 - adr4
java.util.HashMap
mail1:adr1 - adr3 - adr4
mail2:a2
java.util.TreeMap