ComputeIfAbsent method of Map has following declaration:
computeIfAbsent(K key, Function<? super K,? extends V> mappingFunction)
.
Why wasn't parameter declared as Function<K,V>
when K and V types are not used anywhere else?
Now I understand that K and V are very important and they are part of the Map class declaration.
K
and V
are part of the type of the mapping function. So they are actually used. Specifically, they determine the acceptable and most general bounds for the argument type and the return type of the mapping function.
For
Function<? super K,? extends V> mappingFunction
this means that you can pass any function that is able to at least map everything that can serve as a key in your map (thus ? super K
) and maps those keys to values that can be put into the map (thus extends V
). In effect this gives you more flexibility in the choice of the mapping function.
In more theoretical terms: under sub-typing functions are contravariant in its argument type and covariant in its return type. This determines the type of mappingFunction
to Function<? super K,? extends V>
when regarding Map<K, V>
as a function from K
to V
.
Simple example:
Map<String,Object> myMap = ...
Function<Object,String> myFunc = Object::toString;
myMap.computeIfAbsent("42", myFunc);
Is this acceptable?
Well, given the type of myFunc is Function<Object,String>
, and we have a Map<String,Object>
, which sounds like there is a problem. It certainly wouldn't compile if you only accepted Function<K,V>
.
But when you look at it closer, there isn't anything wrong. Not only does the code demonstrably work, it's also easy to see why it works: "42"
is an instance of String
, which has a toString()
method. That method returns a String
, which is of course an Object
. So of course it's fine.
And this "fine"-ness is what is expressed by Function<? super K, ? extends V>
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With