4

在从事纸牌游戏项目时,我试图创建一个新地图,同时已经有一个我想用作 KeySet 的列表。地图必须使用 Player 类型的键,并且每个键都包含一个由单个 组成的值List<Trick>,其中 Player 是一个接口,而 Trick 是一个类。

最初,我尝试使用List<Player> players我拥有的 Stream,然后通过以下方式将其收集到 Map:

private Map<Player, List<Trick>> playerTricks = players.stream()
        .collect(Collectors.toMap(x -> x, ArrayList::new));

但是,我的 IDE IntelliJ 不允许我使用这种格式,因为它说“无法解析构造函数 ArrayList”。

令我惊讶的是,当我删除::-Operator 时,IDE 不再抱怨:

(Collectors.toMap(x -> x, x -> new ArrayList<Trick>()));

虽然我现在确实有没有异常的代码,但我仍然不明白为什么 Scope Resolution Operator 会产生这样的错误。如果有人能正确解释,我将不胜感激。

PS 在寻找解决方案时,我发现了这个 StackOverflow 线程:

将新对象存储为哈希图的值?

它确实涉及类似的问题,但并没有真正解决我面临的问题。

4

1 回答 1

4

第二个参数Collectors.toMap采用 a Function,它采用流类型并将其映射到 new 的值类型Map

Function<? super T,? extends U> valueMapper

首先,::它不像 C++ 中那样称为范围解析运算符,尽管在 Java 中创建方法引用时它的功能有些相似。它只是(简单地)“双冒号运算符”。

方法引用ArrayList::new不匹配Function<Player, List<Trick>>,因为没有ArrayList(Player)构造函数。无法使用此方法参考。您试图忽略该Player参数,但方法引用必须使用它。

当您用 lambda 表达式替换方法引用时x -> new ArrayList<Trick>(),它确实匹配Function<Player, List<Trick>>。您正在使用x,它被隐式定义为Player,并且 lambda 表达式的类型是List<Trick>,它匹配。您忽略了Player xlambda 表达式中的 ,甚至在它调用创建新的ArrayList.

您的 lambda 表达式等同于方法引用,因为您的方法引用尝试查找ArrayList(Player)构造函数,而 lambda 表达式采用Player并忽略它,而只是显式调用无参数ArrayList构造函数。

于 2018-08-02T23:42:40.553 回答