为 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::getKey
和 Map.Entry::getValue
但错误是由其他原因引起的。 Map.Entry::getValue
和 Integer::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
类型
mergeFunction
有 U
类型
将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));
}
注意 一种不需要 mapFactory
的 Collectors.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,则编译器将正确指出类型 String
和 Integer
不兼容。
并且不需要使用语法进行奇怪的操作,我建议您熟悉 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
(没有任何括号)。
而getKey
是Entry
接口声明的实例方法之一
回顾
定义 Function
的正确语法(这是标准的 功能接口 预期作为 Collectors.toMap()
与 方法引用 是:
Map.Entry::getKey
双冒号之前的第一部分是将传递给对象的类型 函数。第二部分是 方法名称 .
从不 在 Java 中的类型之后使用圆括号(不要将对类型的引用与构造函数调用混淆)。在 方法名称 括号被删除是因为语言的设计方式,我猜是因为 方法引用 旨在简洁和表达。
每当我在我的 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::getKey
和 Map.Entry::getValue
但错误是由其他原因引起的。 Map.Entry::getValue
和 Integer::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
类型mergeFunction
有U
类型
将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));
}
注意 一种不需要 mapFactory
的 Collectors.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,则编译器将正确指出类型 String
和 Integer
不兼容。
并且不需要使用语法进行奇怪的操作,我建议您熟悉 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
(没有任何括号)。
而getKey
是Entry
接口声明的实例方法之一
回顾
定义 Function
的正确语法(这是标准的 功能接口 预期作为 Collectors.toMap()
与 方法引用 是:
Map.Entry::getKey
双冒号之前的第一部分是将传递给对象的类型 函数。第二部分是 方法名称 .
从不 在 Java 中的类型之后使用圆括号(不要将对类型的引用与构造函数调用混淆)。在 方法名称 括号被删除是因为语言的设计方式,我猜是因为 方法引用 旨在简洁和表达。