map
中concurrenthashmap
是线程安全的,但不是所有操作都是,例如get()
之后再put()
就不是了,这时使用merge()
确保没有更新会丢失。
因为map.merge()
意味着我们可以原子地执行插入或更新操作,它是线程安全的。
default v merge(k key, v value, bifunction<? super v, ? super v, ? extends v> remappingfunction) { objects.requirenonnull(remappingfunction); objects.requirenonnull(value); v oldvalue = get(key); v newvalue = (oldvalue == null) ? value : remappingfunction.apply(oldvalue, value); if(newvalue == null) { remove(key); } else { put(key, newvalue); } return newvalue; }
该方法接收三个参数,一个 key
值,一个 value
,一个 remappingfunction
。如果给定的key
不存在,它就变成了put(key, value)
;但是,如果key
已经存在一些值,我们 remappingfunction
可以选择合并的方式:
(old, new) -> new
;(old, new) -> old
;(old, new) -> old + new
;(old, new) -> null
。merge()
方法在统计时用的场景比较多,例如:有一个学生成绩对象的列表,对象包含学生姓名、科目、科目分数三个属性,求得每个学生的总成绩。
studententity.java
@data public class studententity { /** * 学生姓名 */ private string studentname; /** * 学科 */ private string subject; /** * 分数 */ private integer score; }
private list<studententity> buildatestlist() { list<studententity> studententitylist = new arraylist<>(); studententity studententity1 = new studententity() {{ setstudentname("张三"); setsubject("语文"); setscore(60); }}; studententity studententity2 = new studententity() {{ setstudentname("张三"); setsubject("数学"); setscore(70); }}; studententity studententity3 = new studententity() {{ setstudentname("张三"); setsubject("英语"); setscore(80); }}; studententity studententity4 = new studententity() {{ setstudentname("李四"); setsubject("语文"); setscore(85); }}; studententity studententity5 = new studententity() {{ setstudentname("李四"); setsubject("数学"); setscore(75); }}; studententity studententity6 = new studententity() {{ setstudentname("李四"); setsubject("英语"); setscore(65); }}; studententity studententity7 = new studententity() {{ setstudentname("王五"); setsubject("语文"); setscore(80); }}; studententity studententity8 = new studententity() {{ setstudentname("王五"); setsubject("数学"); setscore(85); }}; studententity studententity9 = new studententity() {{ setstudentname("王五"); setsubject("英语"); setscore(90); }}; studententitylist.add(studententity1); studententitylist.add(studententity2); studententitylist.add(studententity3); studententitylist.add(studententity4); studententitylist.add(studententity5); studententitylist.add(studententity6); studententitylist.add(studententity7); studententitylist.add(studententity8); studententitylist.add(studententity9); return studententitylist; }
思路:用map
的一组key/value
存储一个学生的总成绩(学生姓名作为key
,总成绩为value
)
map
中不存在指定的key
时,将传入的value
设置为key
的值;key
存在值时,取出存在的值与当前值相加,然后放入map
中。public void normalmethod() { long starttime = system.currenttimemillis(); // 造一个学生成绩列表 list<studententity> studententitylist = buildatestlist(); map<string, integer> studentscore = new hashmap<>(); studententitylist.foreach(studententity -> { if (studentscore.containskey(studententity.getstudentname())) { studentscore.put(studententity.getstudentname(), studentscore.get(studententity.getstudentname()) + studententity.getscore()); } else { studentscore.put(studententity.getstudentname(), studententity.getscore()); } }); log.info("各个学生成绩:{},耗时:{}ms",studentscore, system.currenttimemillis() - starttime); }
map.merge()
很明显,这里需要采用
remappingfunction
的合并方式。
public void mergemethod() { long starttime = system.currenttimemillis(); // 造一个学生成绩列表 list<studententity> studententitylist = buildatestlist(); map<string, integer> studentscore = new hashmap<>(); studententitylist.foreach(studententity -> studentscore.merge( studententity.getstudentname(), studententity.getscore(), integer::sum)); log.info("各个学生成绩:{},耗时:{}ms",studentscore, system.currenttimemillis() - starttime); }
@test public void testall() { // 一般写法 normalmethod(); // merge()方法 mergemethod(); }
00:21:28.305 [main] info cn.van.jdk.eight.map.merge.mapofmergetest - 各个学生成绩:{李四=225, 张三=210, 王五=255},耗时:75ms 00:21:28.310 [main] info cn.van.jdk.eight.map.merge.mapofmergetest - 各个学生成绩:{李四=225, 张三=210, 王五=255},耗时:2ms
merger()
方法使用起来在一定程度上减少了代码量,使得代码更加简洁。同时,通过打印的方法耗时可以看出,merge()
方法效率更高。map.merge()
的出现,和concurrenthashmap
的结合,完美处理那些自动执行插入或者更新操作的单线程安全的逻辑.
如对本文有疑问, 点击进行留言回复!!
NullPointerException: Attempt to invoke virtual method ‘android.content.res.XmlResourceParser androi
关于启动appium-desktop,报错:Cannot extract apk info using apkanalyzer. Falling back to aapt. Original ....
Gradle 发布共享库——如何通过Gradle发布Android依赖库(aar)到 jitpack 公共仓库
Gradle 发布共享库——如何通过Gradle发布java依赖库(jar)到 jitpack 公共仓库(—)
网友评论