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.toMaptakes aFunctionthat 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::newdoesn't matchFunction<Player, List<Trick>>, because there is noArrayList(Player)constructor. This method reference cannot be used. You're attempting to ignore thePlayerargument, 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 thePlayerxin 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 thePlayerand ignores it while just calling the no-argArrayListconstructor explicitly.