你能在Java中向地图添加一个函数对象吗?

时间:2017-02-27 03:08:21

标签: java function

假设我有一个小型演示来计算方法被调用的次数,例如

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()部分抱怨。你有解释吗?除了解决这个问题的方法(同时仍然使用函数对象和地图,而不是两个单独的整数进行计数)。

2 个答案:

答案 0 :(得分:4)

您可以通过在get方法中转换函数来进行编译:

map.get((Function<String, Integer>)this::method2);

但代码仍无效。

每个lambda表达式都会创建一个新的函数类,并且由于Function没有实现hashcode和equals,因此将它们用作映射键的唯一方法是使用相同的实例/对象进行插入和查找。 也就是说,我想不出你为什么想要将一个函数用作映射键。

答案 1 :(得分:1)

@SotiriosDelimanolis暗示,Map.get()接受Object,而不是密钥类型,因此编译器无法推断目标lambda类型。有一些可能的解决方法。

  1. 创建一个临时变量:

    Function<String, Integer> key = this::method1;
    Integer time = map.get(key);
    
  2. 将lambda转换为目标类型:

    Integer time = map.get((Function<String, Integer>)this::method1);
    
  3. 使用接受密钥类型的重载,例如merge()。这也通过将get和put合并到一个语句中来改进你的代码,并且可能不需要构造函数初始化(你真的想初始化为1吗?):

    map.merge(this::method1, 1, Integer::sum);