您可以从Eclipse Collections 使用MutableMapIterable.updateValueWith(K key, Function0<? extends V> factory, Function2<? super V,? super P,? extends V> function, P parameter)。
factory 参数创建一个初始值,如果地图中没有任何值。 function 参数与附加参数一起应用于映射值,以产生新的映射值。 parameter 作为最后一个参数传递给 updateValueWith()。即使键不在地图中,也会调用该函数。所以初始值实际上是应用于factory 和parameter 的输出的function。 function 不能改变值;它应该返回一个新值。在您的示例中,地图值是不可变的字符串,所以我们很好。
在像org.eclipse.collections.impl.map.mutable.ConcurrentHashMap 这样的ConcurrentMaps 中,updateValueWith() 的实现也是线程安全和原子的。 function 不会改变映射值,否则它不是线程安全的,这一点很重要。它应该返回新值。在您的示例中,地图值是不可变的字符串,所以我们很好。
如果您的方法recalculateNewValue() 只是进行字符串连接,那么您可以使用updateValueWith()。
Function0<String> factory = () -> "initial ";
Function2<String, String, String> recalculateNewValue = String::concat;
MutableMap<String, String> map = new ConcurrentHashMap<>();
map.updateValueWith("test", factory, recalculateNewValue, "append1 ");
Assert.assertEquals("initial append1 ", map.get("test"));
map.updateValueWith("test", factory, recalculateNewValue, "append2");
Assert.assertEquals("initial append1 append2", map.get("test"));
您可以使用 Java 8 的 ConcurrentMap.compute(K key, BiFunction remappingFunction) 来完成同样的事情,但它有一些缺点。
ConcurrentMap<String, String> map = new ConcurrentHashMap<>();
map.compute("test", (key, oldValue) -> oldValue == null ? "initial append1 " : oldValue + "append1 ");
Assert.assertEquals("initial append1 ", map.get("test"));
map.compute("test", (key, oldValue) -> oldValue == null ? "initial append1 " : oldValue + "append2");
Assert.assertEquals("initial append1 append2", map.get("test"));
- 没有单独的工厂来处理缺少键的情况,因此 lambda 的主体必须处理值和初始值。
- API 不适合重用 lambda。对
updateValueWith() 的每次调用都共享相同的lambda,但对compute() 的每次调用都会在堆上创建新的垃圾。
注意:我是 Eclipse Collections 的提交者