2019-01-06 一种更优雅的方式 replaceAll()
需求:
对map中的所有值统一增减
基础版本
下面这个方式是可行
的,但是看着不太优雅
public static void main(String[] args) {
Map<Integer, Integer> map = new HashMap<>();
map.forEach((key, value)->map.put(key,map.get(key)-1));
}
误用版本--merge 有副作用
经过一番研究之后发现了一种简单的方式,但是有个限制 merge之后不能发生结构性修改(也就是map中元素数量不能发生变化)
,在当前场景下只要保证merge后不为空值即可
public class MapIncr {
public static void main(String[] args) {
Map<Integer, Integer> map = new HashMap<>();
map.forEach((key, value) -> map.merge(key, -1, Integer::sum));
}
}
关键就是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;
}
可以看到如果新值为空就会被移除掉
最佳版本--replaceAll
replaceAll会对map中的所有元素使用传递进来的BiFunction进行更新.
public class MapIncr {
public static void main(String[] args) {
Map<Integer, Integer> map = new HashMap<>();
map.replaceAll((k,v)->v+1);
}
}
总结
- 基础版本的偏向于命令式编程,遍历map,对map中的每个元素进行处理,处理规则是,这需要使用者说明并编写整个处理流程.
- 最佳版本则更符合函数式编程,我想替换map中的所有值,替换规则是xxx,隐藏了遍历逻辑.很明显,最佳版本的更加清楚明了.
- 至于误用版本,就是对api的错误使用了,之所以保留它,只是想说明: keep digging,there is always a better way,