Pages

HashMap.computeIfAbsent() behavior in Java 9

If in your code you are using computeIfAbsent(), be aware that it has changed its behavior in Java 9. Now you get a ConcurrentModificationException if the mapping function changes the map.

So, for instance, this Fibonacci calculator works fine in Java 8:
class Fibonacci {
    private static final Map<Integer, Long> cache = new HashMap<>();
    static {
        cache.put(0, 0L);
        cache.put(1, 1L);
    }

    public long calculate(int x) {
        return cache.computeIfAbsent(x, n -> calculate(n - 1) + calculate(n - 2));
    }
}
But not if you try to run it in Java 9.

As the computeIfAbsent()'s javadoc states quite clearly, "This method will, on a best-effort basis, throw a ConcurrentModificationException if it is detected that the mapping function modifies this map during computation". If you have a look at the code, you will see that line 1139 is:
if (mc != modCount) { throw new ConcurrentModificationException(); }
And the mc counter is increased a bit below to keep track of any changes in the map due to mappingFunction.

My way out to this issue has been refactoring the Fibonacci calculation to get rid of computeIfAbsent(). Something like that:
public long calculate(int x) {
    if (cache.containsKey(x)) {
        return cache.get(x);
    }

    long lhs = cache.containsKey(x - 1) ? cache.get(x - 1) : calculate(x - 1);
    long rhs = cache.containsKey(x - 2) ? cache.get(x - 2) : calculate(x - 2);
    long result = lhs + rhs;

    cache.put(x, result);
    return result;
}
Well, it's not a beauty. At least it works.

Go to the full post