Java Map computeIfAbsent issue

Viewed 3948

So I found a curiosity with Java's Map computeIfAbsent (using java8) method and I hope someone can tell me why this is happening as I can not really follow the logic behind that issue.

So, I have a Map with a key (obviously) and the value is a list and I use the computeIfAbsent to create a new list when a key is not set yet. Now when I use an Integer as key I can use the following:

List<Object> list = map.computeIfAbsent(1, ArrayList::new);

But when I use a String as key trying to use

List<Object> list = map.computeIfAbsent("key", ArrayList::new);

I get the error that The method computeIfAbsent(String, Function<? super String,? extends List<Object>>) in the type Map<String,List<Object>> is not applicable for the arguments (String, ArrayList::new). Is there just the implementation missing? Using a String key I have to use the method like that, which is then working again.

List<Object> list = map.computeIfAbsent("key", k -> new ArrayList<>());

Maybe someone can enlighten me about that. Thanks :)

2 Answers

The mapping function - Function<? super K, ? extends V> mappingFunction - maps a key to a value, so when the key is Integer, ArrayList::new works, since ArrayList has a constructor that takes an int (the initial capacity). On the other hand, it doesn't have a constructor that takes a String.

Since the key probably shouldn't affect the initial capacity of the ArrayList, you should not use a method reference here (in both cases). Use lambda expression.

To make it clearer:

List<Object> list = map.computeIfAbsent(1, ArrayList::new);

behaves similar to:

List<Object> list = map.computeIfAbsent(1, k -> new ArrayList<>(k));

so it will create an ArrayList with initial capacity of 1.

On the other hand:

List<Object> list = map.computeIfAbsent("key", ArrayList::new);

behaves similar to:

List<Object> list = map.computeIfAbsent("key", k -> new ArrayList<>(k));

where k is a String, so it doesn't pass compilation.

Your second attempt

List<Object> list = map.computeIfAbsent("key", ArrayList::new);

would actually be equal to

List<Object> list = map.computeIfAbsent("key", k -> new ArrayList<>(k));

and since ArrayList has no constructor taking a String as a parameter, it doesn't work. The first example works as it creates a list with one element.

Related