假设我有一个小型演示来计算方法被调用的次数,例如
public class Test {
public static Map<Function<String, Integer>, Integer> map = new HashMap<>();
public Test() {
map.put(this::method1, 0);
map.put(this::method2, 0);
}
public Integer method1(String a) {
Integer time = map.get(this::method1);
map.put(this::method1, time + 1);
return time;
}
public Integer method2(String a) {
Integer time = map.get(this::method2);
map.put(this::method2, time + 1);
return time;
}
}
上面的代码演示了这个想法,但代码没有编译。它没有在map.put()
抱怨;它在map.get()
部分抱怨。你有解释吗?除了解决这个问题的方法(同时仍然使用函数对象和地图,而不是两个单独的整数进行计数)。
答案 0 :(得分:4)
您可以通过在get方法中转换函数来进行编译:
map.get((Function<String, Integer>)this::method2);
但代码仍无效。
每个lambda表达式都会创建一个新的函数类,并且由于Function
没有实现hashcode和equals,因此将它们用作映射键的唯一方法是使用相同的实例/对象进行插入和查找。
也就是说,我想不出你为什么想要将一个函数用作映射键。
答案 1 :(得分:1)
如@SotiriosDelimanolis暗示,Map.get()
接受Object
,而不是密钥类型,因此编译器无法推断目标lambda类型。有一些可能的解决方法。
创建一个临时变量:
Function<String, Integer> key = this::method1;
Integer time = map.get(key);
将lambda转换为目标类型:
Integer time = map.get((Function<String, Integer>)this::method1);
使用接受密钥类型的重载,例如merge()
。这也通过将get和put合并到一个语句中来改进你的代码,并且可能不需要构造函数初始化(你真的想初始化为1吗?):
map.merge(this::method1, 1, Integer::sum);