对于java8的新特性toMap方法,相信有很多人都在工作中用过,接下来就通俗易懂的讲解一下toMap吧
先来看看官网对于toMap方法的解释
toMap有个三个重载的方法,每一个重载方法的详解分别如下
(1)方法1:两个参数
public static <T, K, U> Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,Function<? super T, ? extends U> valueMapper) {
return toMap(keyMapper, valueMapper, throwingMerger(), HashMap::new);
}
(2)方法2:三个参数
public static <T, K, U>
Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,Function<? super T, ? extends U> valueMapper,
BinaryOperator mergeFunction) {
return toMap(keyMapper, valueMapper, mergeFunction, HashMap::new);
}
(3)方法3:四个参数
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 mergeFunction,Supplier mapSupplier)
{
BiConsumer<M, T> accumulator
= (map, element) -> map.merge(keyMapper.apply(element),
valueMapper.apply(element), mergeFunction);
return new CollectorImpl<>(mapSupplier, accumulator, mapMerger(mergeFunction), CH_ID);
}
对于上述三个方法中每个参数做下解释
keyMapper:Key 的映射函数
valueMapper:Value 的映射函数
mergeFunction:当 Key 冲突时,调用的合并方法
mapSupplier:Map 构造器,在需要返回特定的 Map 时使用
补充一个重要的知识点,接下来讲解时会依照这个规则讲解
针对于Map集合,在执行put方法时
map.put(k1,v1);
map.put(k1,v2);
最终集合中保留下来的元素是[k1,v1]
总结:每次往Map集合put添加相同的key值时,后面的key对应的value会覆盖前面的那个key对应的value值。
官网看完了接下来开始进行针对性通俗易懂的解释
(1)针对于两个参数的toMap方法,这里简写为toMap(key,value);
循环执行toMap方法的执行的效果相当于
Map map=new HashMap();
for(循环条件) {
if(map.containsKey()){
throw new RuntimeException(“xxxxxx”);
}
map.put(key,value);
}
解析:在执行toMap方法在收集元素时,如果遇到了重复的key时,它无法解决这个冲突,即此时会报错。
即如果在循环执行toMap方法,并且往map集合插入重复的key时,默认会报错,具体原因可参考源码。
实践案例:
定义一个User(name=zs,age=23,idNumer=13245906)对象,它有三个属性,
1> Map<String,Integer> map=userList.stream().toMap(u->u.getName,u->getAge);
用于收集user类的name与age属性,并且将以key-value键值对的方式插入到map集合中
.
2>Map<String,User> map=userList.stream().toMap(u->u.getName,u->u);
用于收集user类的name与User类的对象,并且将key-value键值对的方式插入到map集合中
.
3>Map<String,User> map=userList.stream().toMap(u->u.getName,Function.identity());
用于收集user类的name与User类的对象,并且将key-value键值对的方式插入到map集合中。
注意:这里的Function.identity()是对传入一个对象,并原封不动的返回的是个简法。
总结:使用这种toMap方法在收集元素时,如果存在重复的Key值时,在收集的过程中会发生冲突,直接导致的后果就是报错。如果想要解决冲突,请参考第二种方法
(2)针对于三个参数的toMap方法,这里简写为两种方式
方式1:toMap(key,value,(k1,k2)->k1);
方式2:toMap(key,value,(k1,k2)->k2);
这两种方式看上去没多大区别,但是意义上却大相径庭,来看看分解后的效果讲解吧
方式1:循环执行toMap方法的执行的效果相当于
Map map=new HashMap();
for(循环条件) {
if(!map.containsKey()){
map.put(key,value);
}
}
总结:方式1中的toMap方法在收集元素时,如果遇到了重复的key时,它会放弃收集后面的那个key对应的元素。(k1,k2)->k1就表示k1==k2相同时,保留前面的k1那个元素,放弃k2那个元素。
方式2:循环执行toMap方法的执行的效果相当于
Map map=new HashMap();
for(循环条件) {
map.put(key,value);
}
总结:方式1中的toMap方法在收集元素时,如果遇到了重复的key时,它会放弃收集前面的那个key对应的元素。(k1,k2)->k2就表示k1==k2相同时,保留后面最新收集的k2那个元素,放弃以前收集过的k1那个元素。
实践案例:
定义一个User(name=zs,age=23,idNumer=13245906)对象,它有三个属性
方式1:
Map<String,Integer> map=userList.stream().toMap(u->u.getName,u->getAge,(k1,k2)->k1);
用于收集user类的name与age属性,并且将以key-value键值对的方式插入到map集合中.
如果在收集过程中发现重名的name值,则保留原先集合中存在的那个key及其对应的value值。舍弃最新待收集的key及其对应的value
.
方式2:
Map<String,Integer> map=userList.stream().toMap(u->u.getName,u->getAge,(k1,k2)->k2);
用于收集user类的name与age属性,并且将以key-value键值对的方式插入到map集合中.
如果在收集过程中发现重名的name值,则舍弃原先集合中存在的那个key及其对应的value值。保留最新待收集的key及其对应的value
(3)针对于四个参数的toMap方法,这里简写为多种方式
方式1:toMap(key,value,(k1,k2)->k1,HashMap::New);
toMap(key,value,(k1,k2)->k2,HashMap::New);
方式2:toMap(key,value,(k1,k2)->k1,TreeMap::New);
toMap(key,value,(k1,k2)->k2,TreeMap::New);
可以对收集到TreeMap集合中的元素按照相应的排序规则进行排序
方式3:toMap(key,value,(k1,k2)->k1,LinkedHashMap::New);
toMap(key,value,(k1,k2)->k2,LinkedHashMap::New);
可以保证收集到LinkedHashMap集合中的元素依旧保持原来的顺序
实践举例:这三种方式其实没多大区别,我们拿其中一个方式举例
针对方式3的toMap(key,value,(k1,k2)->k2,LinkedHashMap::New); 你可以这样理解。
Map map=new LinkedHashMap();
for(循环条件) {
map.put(key,value);
}
解析:在执行toMap方法在收集元素时,创建一个LinkedHashMap集合,然后使用该集合来收集元素,其余的效果同toMap(key,value,(k1,k2)->k2);一样。
经过刚刚的举例讲解,其实也能大概理解这种方式的含义了,它就是在执行toMap方法时构建一个自定义的Map容器,然后循环执行toMap方法时往集合里收集元素,所以该系列方法同三个参数的toMap方法原理几乎一摸一样。
默认情况下,toMap(key,value)与toMap(key,value,(k1,k2)->k1);方法在收集元素时都是构建的一个HashMap容器,然后使用HashMap容器去存储元素,但是HashMap集合我们都知道它是无序的,且无法针对集合中的元素进行排序。所以如果你在工作中有需要针对集合元素进行排序的需求时请使用四个参数的toMap方法
总结
(1)toMap(key,value),创建一个HashMap集合用于收集元素,当在收集时出现了重复的key值,它会直接报错,并且中断收集元素到HashMap集合
(2)toMap(key,value,(k1,k2)->k1)创建一个HashMap集合用于收集元素,当在收集时出现了重复的key值时,它会根据(k1,k2)->k1)或者(k1,k2)->k2)这两种规则解决key值重复的冲突并收集元素到HashMap集合
(3) toMap(key,value,(k1,k2)->k2,LinkedHashMap::New)
创建一个LinkedHashMap集合用于收集元素,当在收集时出现了重复的key值时,它会根据(k1,k2)->k1)或者(k1,k2)->k2)这两种规则解决key值重复的冲突并收集元素到LinkedHashMap集合