Assume that you have a List
of numbers. The values in the List
can be of type Integer
, Double
etc. When you declare such a List
it is possible to declare it using a wildcard (?
) or without a wildcard.
final List<Number> numberList = Arrays.asList(1, 2, 3D); final List<? extends Number> wildcardList = Arrays.asList(1, 2, 3D);
So, now I want to stream
over the List
and collect
it all to a Map
using the Collectors.toMap
(obviously the code below is just an example to illustrate the problem). Lets start off by streaming the numberList
:
final List<Number> numberList = Arrays.asList(1, 2, 3D, 4D); numberList.stream().collect(Collectors.toMap( // Here I can invoke "number.intValue()" - the object ("number") is treated as a Number number -> Integer.valueOf(number.intValue()), number -> number));
But, I can not do the same operation on the wildcardList
:
final List<? extends Number> wildCardList = Arrays.asList(1, 2, 3D); wildCardList.stream().collect(Collectors.toMap( // Why is "number" treated as an Object and not a Number? number -> Integer.valueOf(number.intValue()), number -> number));
The compiler complains on the call to number.intValue()
with the following message:
Test.java: cannot find symbol
symbol: method intValue()
location: variable number of type java.lang.Object
From the compiler error it is obvious that the number
in the lambda is treated as an Object
instead of as a Number
.
So, now to my question(s):
List
, why is it not working like the non-wildcard version of the List
? number
variable in the lambda considered to be an Object
instead of a Number
?Collectors.toMap() with Mapper and Merge FunctionsIt's input are two values that is the two values for which keyMapper returned the same key, and merges those two values into a single one.
The toList() method of Collectors Class is a static (class) method. It returns a Collector Interface that gathers the input data onto a new list. This method never guarantees type, mutability, serializability, or thread-safety of the returned list but for more control toCollection(Supplier) method can be used.
A parallel stream is performed one or more elements at a time. Thus the map() would preserve the encounter of the stream order but not the original List's order.
collect() is one of the Java 8's Stream API's terminal methods. It allows us to perform mutable fold operations (repackaging elements to some data structures and applying some additional logic, concatenating them, etc.) on data elements held in a Stream instance.
It's the type inference that doesn't get it right. If you provide the type argument explicitly it works as expected:
List<? extends Number> wildCardList = Arrays.asList(1, 2, 3D); wildCardList.stream().collect(Collectors.<Number, Integer, Number>toMap( number -> Integer.valueOf(number.intValue()), number -> number));
This is a known javac bug: Inference should not map capture variables to their upper bounds. The status, according to Maurizio Cimadamore,
a fix was attempted then backed out as it was breaking cases in 8, so we went for a more conservative fix in 8 while doing the full thing in 9
Apparently the fix has not yet been pushed. (Thanks to Joel Borggrén-Franck for pointing me in the right direction.)
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