I have a usecase where I have to
You can use MutableMapIterable.updateValueWith(K key, Function0 extends V> factory, Function2 super V,? super P,? extends V> function, P parameter) from Eclipse Collections.
The factory
argument creates an initial value if none is in the map. The function
argument is applied to the map value along with an additional parameter to come up with a new map value. That parameter
is passed as the final argument to updateValueWith()
. The function is called even in the case where the key wasn't in the map. So the initial value is really the function
applied to the output of factory
and parameter
. The function
must not mutate the value; it should return a new value. In your example, the map values are Strings which are immutable so we're fine.
In ConcurrentMaps like org.eclipse.collections.impl.map.mutable.ConcurrentHashMap
, the implementation of updateValueWith()
is also thread-safe and atomic. It’s important that function
does not mutate the map values or it wouldn’t be thread-safe. It should return new values instead. In your example, the map values are Strings which are immutable so we're fine.
If your method recalculateNewValue()
just does String concatenation, here's how you might use updateValueWith()
.
Function0 factory = () -> "initial ";
Function2 recalculateNewValue = String::concat;
MutableMap 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"));
You can use Java 8's ConcurrentMap.compute(K key, BiFunction remappingFunction) to accomplish the same thing, but it has a few disadvantages.
ConcurrentMap 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"));
updateValueWith()
shares the same lambdas, but every call to compute()
creates new garbage on the heap. Note: I am a committer for Eclipse Collections