Reputation: 5736
Say I have a small demo to count the number of times a method is called, e.g.
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;
}
}
The code above demoed the idea, but the code doesn't compile. It does not complain at the map.put()
; it complains at the map.get()
parts. Do you have an explanation? As well as a way to fix this (while still using function objects and a map, not two individual integers to do the counting).
Upvotes: 0
Views: 1758
Reputation: 8310
You can make this compile by casting the function in the get method:
map.get((Function<String, Integer>)this::method2);
But the code still won't work.
Each lambda expression creates a new function class, and since Function
does not implement hashcode and equals, the only way you could use them as map keys is if you use the same instance/object for the insertion and lookup.
That said, I can't think of a reason why you would ever want to use a function as a map key.
Upvotes: 4
Reputation: 50726
As @SotiriosDelimanolis hinted, Map.get()
accepts Object
, not the key type, so the compiler is unable to infer the target lambda type. There are a few possible workarounds.
Create a temporary variable:
Function<String, Integer> key = this::method1;
Integer time = map.get(key);
Cast the lambda to the target type:
Integer time = map.get((Function<String, Integer>)this::method1);
Use an overload that does accept the key type, like merge()
. This also improves your code by merging the get and put into one statement, and possibly making the constructor initialization unnecessary (did you really mean to initialize to 1?):
map.merge(this::method1, 1, Integer::sum);
Upvotes: 1