While working on a card game project, I was trying to create a new Map while already having a List I wanted to use as a KeySet. The Map has to use Keys of type Player and have each of them hold a Value consisting of a single List<Trick>
, with Player being an Interface and Trick - a class.
Initially I tried to use a Stream of the List<Player> players
I had and then collect it to a Map in the following way:
private Map<Player, List<Trick>> playerTricks = players.stream()
.collect(Collectors.toMap(x -> x, ArrayList::new));
My IDE, IntelliJ, however did not allow me this format, as it said "Cannot resolve Constructor ArrayList".
Much to my surprise, the IDE stopped complaining when I removed the ::
-Operator:
(Collectors.toMap(x -> x, x -> new ArrayList<Trick>()));
While I now do have code with no Exceptions, I still can't understand why the Scope Resolution Operator would produce such an error. I'd be grateful if anyone was to explain it properly.
P.S. While searching to a solution, I found this StackOverflow Thread:
Storing a new object as the value of a hashmap?
It does concern a similar issue, but doesn't really address the problem I was facing.
The second parameter of
Collectors.toMap
takes aFunction
that takes the stream type and maps it to the value type of the newMap
.First,
::
isn't called the scope resolution operator like in C++, although it functions somewhat similarly when creating a method reference in Java. It's just (simply) "double-colon operator".The method reference
ArrayList::new
doesn't matchFunction<Player, List<Trick>>
, because there is noArrayList(Player)
constructor. This method reference cannot be used. You're attempting to ignore thePlayer
argument, but the method reference must use it.When you replaced the method reference with a lambda expression
x -> new ArrayList<Trick>()
, that does matchFunction<Player, List<Trick>>
. You're takingx
, which is implicitly defined to bePlayer
, and the type of the lambda expression isList<Trick>
, which matches. You're ignoring thePlayer
x
in the lambda expression, before it would even get to the call to create a newArrayList
.Your lambda expression is not equivalent to the method reference, because your method reference attempts to find a
ArrayList(Player)
constructor while the lambda expression takes thePlayer
and ignores it while just calling the no-argArrayList
constructor explicitly.