Java8 Map中新增的方法使用总结
前言
得益于Java8的default方法特性,Java8对Map增加了不少实用的默认方法,像getOrDefault,forEach,replace,replaceAll,putIfAbsent,remove(key,value),computeIfPresent,computeIfAbsent,compute和merge方法。另外与Map相关的Map.Entry也新加了多个版本的comparingByKey和comparingByValue方法。
为达到熟练运用上述除getOrDefault和forEach外的其他方法,有必要逐一体验一番,如何调用,返回值以及调用后的效果如何。看看每个方法不至于Java8那么多年还总是 if(map.containsKey(key))...那样的老套操作。
前注:Map新增方法对 present的判断是map.containsKey(key)&&map.get(key)!=null,简单就是 map.get(key)!=null,也就是即使key存在,但对应的值为null的话也视为absent。absent就是map.get(key)==null。
不同Map实现对key/value是否能为null有不同的约束,HashMap,LinkedHashMap,key和value都可以为null值,TreeMap的key为不能为null,但value可以为null,而Hashtable,ConcurrentMap则key和value都不同为null。一句话absent/present的判断是map.get(key)是否为null。
方法介绍的顺序是它们相对于本人的生疏程度而定的。每个方法介绍主要分两部分,参考实现代码与示例代码执行效果。参考实现代码摘自JDK官方的MapJavaDoc。
putIfAbsent方法
方法原型VputIfAbsent(Kkey,Vvalue), 如果key不存在或相关联的值为null,则设置新的key/value值。
参考实现:
Vv=get(key); if(v==null){ v=put(key,value); } returnv;
如果原map中对应key的值为为null返回旧值,或者返回新的value值
示例及效果:
Stringret; Mapmap=newHashMap<>(); ret=map.putIfAbsent("a","aaa");//ret为"aaa",map为{"a":"aaa"} ret=map.putIfAbsent("a","bbb");//ret为"aaa",map还是{"a":"aaa"} map.put("b",null); ret=map.putIfAbsent("b","bbb");//ret为"bbb",map为{"a":"aaa","b":"bbb"}
computeIfPresent方法
方法原型VcomputeIfPresent(Kkey,BiFunctionremappingFunction),如果指定的key存在并且相关联的value不为null时,根据旧的key和value计算newValue替换旧值,newValue为null则从map中删除该key;key不存在或相应的值为null时则什么也不做,方法的返回值为最终的map.get(key)。
参考实现:
if(map.get(key)!=null){ VoldValue=map.get(key); VnewValue=remappingFunction.apply(key,oldValue); if(newValue!=null) map.put(key,newValue); else map.remove(key); }
示例及效果:
Stringret; Mapmap=newHashMap<>(); ret=map.computeIfPresent("a",(key,value)->key+value);//retnull,map为{} map.put("a",null);//map为["a":null] ret=map.computeIfPresent("a",(key,value)->key+value);//retnull,map为{"a":null} map.put("a","+aaa"); ret=map.computeIfPresent("a",(key,value)->key+value);//ret"a+aaa",map为{"a":"a+aaa"} ret=map.computeIfPresent("a",(key,value)->null);//ret为null,map为{},计算出的null把key删除了
计算出的值为null时直接删除key而不是设置对应key的值为null,这能照顾到值不能为null的Map实现,如Hashtable和ConcurrentMap。
computeIfAbsent方法
方法原型VcomputeIfAbsent(Kkey,FunctionmappingFunction),与上一个方法相反,如果指定的key不存在或相关的value为null时,设置key与关联一个计算出的非null值,计算出的值为null的话什么也不做(不会去删除相应的 key)。如果key存在并且对应value为null的话什么也不做。同样,方法的返回值也是最终的map.get(key)。
参考实现:
if(map.get(key)==null){ VnewValue=mappingFunction.apply(key); if(newValue!=null) map.put(key,newValue); }
示例及效果:
Stringret; Mapmap=newHashMap<>(); ret=map.computeIfAbsent("a",key->key+"123");//ret"a123",map为{"a":"a123"} ret=map.computeIfAbsent("a",key->key+"456");//ret"a123",map为{"a":"a123"} map.put("a",null); ret=map.computeIfAbsent("a",key->key+"456");//ret"a456",map为{"a":"a456"} ret=map.computeIfAbsent("a",key->null);//ret为"a456",map为{"a":"a456"}
replace(Kkey,Vvalue)方法
只要key存在,不管对应值是否为 null,则用传入的value替代原来的值。即使传入的value是null也会用来替代原来的值,而不是删除,注意这对于value不能为 null值的 Map 实现将会造成NullPointerException。key不存在不会修改Map的内容,返回值总是原始的map.get(key)值。
参考实现:
if(map.containsKey(key)){ returnmap.put(key,value); }else returnnull;
示例及效果:
Stringret; Mapmap=newHashMap<>(); ret=map.replace("a","abc");//ret为null,map为{} map.put("a","ddd"); ret=map.replace("a","abc");//ret为"ddd",map为{"a":"abc"} ret=map.replace("a",null);//ret为"abc",map为{"a":null} ret=map.replace("a","ddd");//ret为null,map为{"a":"ddd"}
replace(Kkey,VoldValue,VnewValue)
当且仅当key存在,并且对应值与oldValue不相等,才用newValue作为key的新相关联值,返回值为是否进行了替换。
参考实现:
if(map.containsKey(key)&&Objects.equals(map.get(key),value)){ map.put(key,newValue); returntrue; }else returnfalse;
示例及效果:
booleanret; Mapmap=newHashMap<>(); ret=map.replace("a",null,"aaa");//ret为false,map为{} map.put("a",null); ret=map.replace("a",null,"aaa");//ret为true,map为{"a":"aaa"} ret=map.replace("a","aaa",null);//ret为true,map为{"a":null} ret=map.replace("a","aaa","bbb");//ret为false,map为{"a":null}
replaceAll方法
方法原型voidreplaceAll(BiFunctionfunction)。它更像一个传统函数型语言的map函数,即对于Map中的每一个元素应用函数function,输入为key和 value。
参考实现:
for(Map.Entryentry:map.entrySet()) entry.setValue(function.apply(entry.getKey(),entry.getValue()));
示例及效果:
Mapmap=newHashMap<>(); map.put("a","aaa"); map.put("b","bbb");//map为{"a":"aaa","b":"bbb"} map.replaceAll((key,value)->key+"-"+value);//map为{"a":"a-aaa","b":"b-bbb"}
remove(key,value)
这个也不用多说,key与value都匹配时才删除。
参考实现:
if(map.containsKey(key)&&Objects.equals(map.get(key),value)){ map.remove(key); returntrue; }else returnfalse;
compute方法
方法原型Vcompute(Kkey,BiFunctionremappingFunction),它是computeIfAbsent与computeIfPresent 的结合体。也就是既不管key存不存在,也不管key对应的值是否为null,compute死活都要设置与key相关联的值,或者计算出的值为null时删除相应的key,返回值为最终的map.get(key)。
参考实现:
VoldValue=map.get(key); VnewValue=remappingFunction.apply(key,oldValue); if(oldValue!=null){ if(newValue!=null) map.put(key,newValue); else map.remove(key); }else{ if(newValue!=null) map.put(key,newValue); else returnnull; }
示例及效果:
Stringret; Mapmap=newHashMap<>(); ret=map.compute("a",(key,value)->"a"+value);//ret="anull",map={"a":"anull"} ret=map.compute("a",(key,value)->"a"+value);//ret="aanull",map={"a":"aanull"} ret=map.compute("a",(key,value)->null);//ret=null,map={}
merge方法
方法原型Vmerge(Kkey,Vvalue,BiFunctionremappingFucntion),这是至今来说比较神秘的一个方法,尚未使用到它。如果指定的key不存在,或相应的值为null时,则设置 value为相关联的值。否则根据key对应的旧值和value计算出新的值newValue,newValue为null时,删除该key,否则设置key对应的值为 newValue。方法的返回值也是最终的 map.get(key)值。
参考实现:
VoldValue=map.get(key); VnewValue=(oldValue==null)?value: remappingFunction.apply(oldValue,value); if(newValue==null) map.remove(key); else map.put(key,newValue);
注意value不能为null值
示例及效果:
Stringret; Mapmap=newHashMap<>(); ret=map.merge("a","aa",(oldValue,value)->oldValue+"-"+value);//ret="aa",map={"a":"aa"} ret=map.merge("a","bb",(oldValue,value)->oldValue+"-"+value);//ret="aa-bb",map={"a":"aa-bb"} ret=map.merge("a","bb",(oldValue,value)->null);//ret=null,map={} map.put("a",null); ret=map.merge("a","aa",(oldValue,value)->oldValue+"-"+value);//ret="aa",map={"a":"aa"} map.put("a",null); ret=map.merge("a","bb",(oldValue,value)->null);//ret="bb",map={"a":"bb"} ret=map.merge("a",null,(oldValue,value)->oldValue+"-"+value);//NullPointerException,value不能为null
Map.EntrycomparingByKey和 comparingByValue方法
另外介绍一下Map.Entry新加的两个排序方法,它们分别有无参与带Comparator参数可嵌套使用的两个版本。comparingByKey(),comparingByKey(Comparatorcmp),comparingByValue()和comparingByValue(Comparatorcmp)。
示例代码如下:
map.entrySet().stream().sorted(Map.Entry.comparingByKey()).collect(Collectors.toList()); map.entrySet().stream().sorted(Map.Entry.comparingByKey(String::compareTo)).collect(Collectors.toList()); map.entrySet().stream().sorted(Map.Entry.comparingByValue()).collect(Collectors.toList()); map.entrySet().stream().sorted(Map.Entry.comparingByValue(String::compareTo)).collect(Collectors.toList());
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对毛票票的支持。