Kotlin has had an extension function ConcurrentMap.getOrPut from the beginning (1.0). This has the same signature as Java's computeIfAbsent and does a similar thing, but with some subtle differences:
getOrPutcan put a null value into the entry, whereascomputeIfAbsentdoesn't support it.getOrPutdoes not guarantee that the default function will only be called once, whereas Java'scomputeIfAbsentdoes guarantee that.When
getOrPutwas released, the latest Java version was Java 8. In Java 8,computeIfAbsentalways locked the entry even if the value was already there. Therefore, Kotlin may have had better performance because it doesn't lock when it doesn't need to.
However, in recent versions of Java (I've just checked 17) the locking overhead mentioned in point 3 is no longer there. So Kotlin's getOrPut no longer has that advantage, but it has the disadvantage of point 2. Under what circumstances should we continue to use getOrPut nowadays (assuming we don't want to put a null into a map) or should it now be considered "legacy"?
You have pointed some very interesting facts for both methods.
Please consider an additional one which will be a reason to use
getOrPut.ComputeIfAbsentensures atomicity. This means that this method can and will block other threads during computation to ensure atomicity.From doc
But
getOrPutdoes not ensure atomicity.From doc
This would mean that in a use case scenario, where atomicity is not important to you,
getOrPutwill offer performance benefits in comparison withcomputeIfAbsent.