Skip to content

Java8的Map接口中2个便捷函数安利

最近刷leetcode时解锁了两个Map<>接口中快速增删key和value的函数,Map.merge()和Map.compute()

· 3 min ·

Java8给这门语言带来了函数式编程的春风,使用lambda算子和stream流,让coding操作大道至简。

Map接口是哈希表的常用接口,也是集合框架中重要的组成部分,在对key和value进行增删改查时,往往需要不断判断if和else的嵌套编码操作,并使用contains()put(),putIfAbsent(),putIfPresent(),remove()等内置函数,使得代码冗余且复杂。

丑陋的新增与删除#

例如,有以下丑陋臃肿的代码:

if (!map.containsKey(key)) {
map.put(key, 1);
} else {
map.put(key, map.get(key) + 1);
}

这种操作经常出现在对新增一个key时候,key不存在则需要调用put,存在时则先拿到value,再put。

第二个样例:

if (map.containsKey(key)) {
map.put(key, map.get(key) - 1);
if (map.get(key) == 0) {
map.remove(key);
}
}

这种操作也很常见,出现在对key对应的value进行扣减1的操作,如果value扣减到0就删除这个key,也是频繁调用containsKey()put()get()等函数,代码异常臃肿。

简化操作#

Java 8 的 merge 和 compute 的出现,直接让这种重复的模板代码消失了。

merge() - 旧值替换新值#

V merge(K key, V value, BiFunction<V, V, V> remappingFunction)

merge()方法接受key,默认值value,以及value存在时候的remappingFunction,它是一个BiFunction类型接口,接受三个范型参数T,U,R,表示两个输入类型和一个输出类型。

merge()操作如下:

因此上述新增操作可以简化为:

map.merge(c, 1, Integer::sum);

表示若c对应key不存在则插入(key,1),否则将插入(key,value+1),实现了丑陋代码的改进。

compute() - 可定制统一更新入口#

compute()一般用在需要复杂逻辑的处理地方,比如根据某些条件删除key或者更新特定的value值。

V compute(K key, BiFunction<K, V, V> remappingFunction)

可以看到,compute()函数的入参就比merge()少了一个value,这并不是说没有默认值,而是将这个默认值直接使用remappingFunction的返回值进行替换。

例如,remappingFunction返回一个1,那就将value设置为1并put,如果返回null则将这个entry删除。

所以,之前的删除代码可以简化为:

map.compute(c, (k, v) -> (v == null || v == 1) ? null : v - 1);

注意这里的判空逻辑,需要格外判断v==null是否这个entry不存在,不然会走v-1引起NPE。代码语义是如果value存在则减1,减到0就删除。因此使用compute()时需要更加谨慎一些。

总结#

如果能够熟练使用以上两个函数式编程的方法,相信会对哈希操作得心应手。