为 Map.Entry::getKey 发出合并两个映射时的编译错误

Compilation error while merging two Maps is being issued for Map.Entry::getKey

每当我在我的 public 方法的流中使用 Map.Entry::getKey 时,我都会遇到一个问题,因为我的方法不是 static。我什至尝试制作我的方法 static,但它没有用。

下面是编译 错误 我使用 Map.Entry()::getKey() :

Non-static method cannot be referenced from a static context

我的代码

/***
 * Merge 2 Maps and add the values together if they are in both maps
 * 
 * firstMap = {"Eggs": 3, "Cereal": 1}
 * secondMap = {"Eggs": 10, "Coke": 23, "Cereal": 1}
 * 
 * Answer = {"Eggs": 13, "Coke": 23, "Cereal": 2}
 * Notice that the Eggs are now 13
 * 
 * @param firstMap
 * @param secondMap
 * @return
 */
public Map<String, Integer> mergeAndAddValues(Map<String, String> firstMap, Map<String, String> secondMap) {

    return Stream.of(firstMap, secondMap)
            .flatMap(map -> map.entrySet().stream())
            .collect(Collectors.toMap(
                       Map.Entry()::getKey,
                       Map.Entry::getValue,
                       Integer::sum,
                       HashMap::new));
}

您可以使用 Map.Entry::getKeyMap.Entry::getValue 但错误是由其他原因引起的。 Map.Entry::getValueInteger::sum return 不同类型。

toMap方法的定义解释原因:

public static <T, K, U, M extends Map<K, U>> Collector<T, ?, M> toMap(
    Function<? super T, ? extends K> keyMapper, 
    Function<? super T, ? extends U> valueMapper, 
    BinaryOperator<U> mergeFunction, 
    Supplier<M> mapFactory);

在定义中你可以看到:

  • valueMapper? extends U 类型
  • mergeFunctionU 类型

将firstMap和secondMap的类型从Map<String, String>改为Map<String, Integer>,没有报错。这是因为 Map.Entry::getValue 编辑的类型 return 从 String 更改为 Integer

这里是最终结果:

public Map<String, Integer> mergeAndAddValues(Map<String, Integer> firstMap, Map<String, Integer> secondMap) {
    return Stream.of(firstMap, secondMap)
                 .flatMap(map -> map.entrySet().stream())
                 .collect(Collectors.toMap(
                        Map.Entry::getKey, Map.Entry::getValue, Integer::sum, HashMap::new));
    }
}

方法参数的类型为 Map<String, String>,return 类型为 Map<String, Integer>

为了修复您的方法,您需要将 Map.Entry<String, String> 类型的 条目 强制转换为 条目 Map.Entry<String, Integer>.

可以通过在嵌套流中应用 map() 操作来完成。静态方法 Map.entry() 用于在现有条目的基础上创建新的 条目 。我假设所有字符串都只由数字组成,否则你需要在解析它们之前应用额外的清除。

public Map<String, Integer> mergeAndAddValues(Map<String, String> firstMap,
                                              Map<String, String> secondMap) {

    return Stream.of(firstMap, secondMap)
            .flatMap(map -> map.entrySet().stream()
                    .map(entry -> Map.entry(entry.getKey(),
                            Integer.valueOf(entry.getValue()))))
            .collect(Collectors.toMap(
                       Map.Entry::getKey,
                       Map.Entry::getValue,
                       Integer::sum));
}

注意 一种不需要 mapFactoryCollectors.toMap 风格(即只接受三个参数的 Collectors.toMap 版本) 被使用是因为默认情况下你会得到一个 HashMap 作为结果。

手动提供 HashMap::new 不会给您带来任何麻烦,相反,您的代码会变得更加严格,如果将来 HashMap 将被性能更高的通用实现所取代Map您将不会免费获得它,因为您的代码将需要更改。

I even tried making my method static ... I am getting from using Map.Entry()::getKey()

Non-static method cannot be referenced from a static context

此问题与静态或实例方法无关,不幸的是,错误消息不是很有帮助的情况很少见。如果您将这些方法引用替换为 lambda,则编译器将正确指出类型 StringInteger 不兼容。

并且不需要使用语法进行奇怪的操作,我建议您熟悉 lambdas and method references 上的这些教程。

lambda 表达式 方法引用 都用于提供 函数接口的实现,它是一个接口,定义了一个且只有一个抽象方法。 IE。 lambda 方法参考 都应该实现这个 单一方法 .

Collectors.toMap() 期望的所有参数都是 函数接口 built-in in Java.

如果由函数接口定义的行为植入已经存在(即你在某个地方有一个方法,它执行在接口应该做),你可以通过方法参考.

来使用它

有四种种方法引用(引自上面引用的Oracles教程 ):

  • 引用静态方法ContainingClass::staticMethodName
  • 引用特定对象的实例方法containingObject::instanceMethodName
  • 引用特定类型的任意对象的实例方法ContainingType::methodName
  • 对构造函数的引用ClassName::new

注意 方法引用语法不需要括号,既不在类型之后,也不在方法名称之后。

所以正确的语法是 Map.Entry::getKey,这是对特定类型的任意对象的 实例 方法的 引用 。 IE。 type Map.Entry 实际上意味着流的一个元素(一个对象,而不是一个接口)。

提示: Entry是一个嵌套接口,表示一个key-value对,定义在Map接口里面。因此,引用它的正确语法是 Map.Entry(没有任何括号)。

getKeyEntry接口声明的实例方法之一

回顾

定义 Function 的正确语法(这是标准的 功能接口 预期作为 Collectors.toMap() 方法引用 是:

Map.Entry::getKey

双冒号之前的第一部分是将传递给对象的类型 函数。第二部分是 方法名称 .

从不 在 Java 中的类型之后使用圆括号(不要将对类型的引用与构造函数调用混淆)。在 方法名称 括号被删除是因为语言的设计方式,我猜是因为 方法引用 旨在简洁和表达。