counts.computeIfAbsent(key, k -> new LongAdder())
This entire expression can go one of two ways:
key
is already in the counts
map. In this case, the 'computer' function (k -> new LongAdder()
) is completely ignored; it isn't run at all. Instead, the value associated with that key is returned.
key
is not in the counts
map. In this case, the 'computer' function is executed once, and the value it returns is now associated with the key.
In other words, it's identical to:
LongAdder result;
if (counts.containsKey(key)) result = counts.get(key);
else {
result = new LongAdder();
counts.put(key, result);
}
return result;
Which is a mouthful, potentially less efficient, and potentially non-atomic whereas .computerIfAbsent
can be atomic if you use the right implementation (such as ConcurrentHashMap
).
Here's the clue: You then invoke .increment()
on this result, regardless of whether we're in the #1 case or the #2 case.
In other words:
First 'row' is seen, computeIfAbsent
ends up executing the lambda and thus, runs something like counts.put(k, new LongAdder())
and THEN you call .increment()
on this.
Next, the second 'row' is seen, computeIfAbsent
ends up being equivalent to counts.get(key)
, and you call .increment()
on that. Which is the same LongAdder we made when we saw the first 'row', and thus this is the second time you are invoking increment()
on it.
It's not computeIfAbsent
that's incrementing anything. It's the .increment()
that increments something.