Java doesn't allow any form of short-circuiting save the built-in cases, sadly - all method calls result in the arguments being fully evaluated before control passes to the method. Thus you couldn't do this with "normal" syntax; you'd need to manually wrap up the calculation inside a Callable
or similar, and then explicitly invoke it.
In this case I find it difficult to see how it could work anyway, though. putIfAbsent
works on the basis of being an atomic, non-blocking operation. If it were to do what you want, the sequence of events would roughly be:
- Check if
key
exists in the map (this example assumes it doesn't)
- Evaluate
calculatedValue
(probably expensive, given the context of the question)
- Put result in map
It would be impossible for this to be non-blocking if the value didn't already exist at step two - two different threads calling this method at the same time could only perform correctly if blocking happened. At this point you may as well just use synchronized
blocks with the flexibility of implementation that that entails; you can definitely implement what you're after with some simple locking, something like the following:
private final Map<K, V> map = ...;
public void myAdd(K key, Callable<V> valueComputation) {
synchronized(map) {
if (!map.containsKey(key)) {
map.put(key, valueComputation.call());
}
}
}