I have a hashMap with an arrayList as its value. I would like to use the computeIfAbsent method to efficiently create the list when a key is not in the map. Then I tried to use ArrayList::new
instead of k -> new ArrayList<Integer>()
to make the code more clear, but got "invalid capacity" error if the key is a negative number.
Map<Integer, List<Integer>> map = new HashMap<>();
map.computeIfAbsent(-4, x -> new ArrayList<Integer>());//This is OK
map.computeIfAbsent(-5, ArrayList::new);//This gives error
java.lang.IllegalArgumentException: Illegal Capacity: -5
Looks like the key is passed to the constructor. Could anyone tell me how this happens? Is it possible I can still use method reference in this case to create the arrayList?
CodePudding user response:
This is how the computeIfAbsent
method defined:
From the class java.util.HashMap
source code:
@Override
public V computeIfAbsent(K key,Function<? super K, ? extends V> mappingFunction) {
... // some code
V v = mappingFunction.apply(key); // create value
// ... put value into the map itself
}
So we're talking about the mappingFunction
here: it has to accept one parameter which is in "runtime" is a key (the first parameter to computeIfAbsent
)
So Java "matches" this Function to the constructor of ArrayList
that accepts one (int) parameter here, because this is how method inference works, otherwise it won't even compile.
Now, here is a constructor of java.util.ArrayList
with one int parameter:
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "
initialCapacity);
}
}
Since the key is "-5" in your example, this constructor is called with "-5" at the end of the day. It enters the "else" block and hence the exception...
When you use the first construction:
map.computeIfAbsent(-4, x -> new ArrayList<Integer>());
"x" will resolve to -4 but its ok because you don't pass into the constructor of ArrayList, or, in other words you don't use it in the mapping function.