As part of arbitrary method references:
Why this is allowed?
Predicate<String> p1 = String::isEmpty;
And why this is not allowed?
BiConsumer<HashMap<String,Integer>, Integer> b1 = HashMap<String,Integer>::put;
-
Do you mean now or not?Roland Illig– Roland Illig2017年03月26日 01:31:06 +00:00Commented Mar 26, 2017 at 1:31
-
Understood, because in the above case the arguments for put cannot be inferred. This will work BiConsumer<HashSet<Integer>, Integer> b1 = HashSet<Integer>::add;Vijay Narayanan– Vijay Narayanan2017年03月26日 01:35:02 +00:00Commented Mar 26, 2017 at 1:35
2 Answers 2
In your first example, you're creating a Predicate which takes one String as an input. This matches String.isEmpty() which does not take any arguments. The predicate only operates on the string instance.
As for the second example, let's examine the put method:
public V put(K key, V value)
Since you're using a HashMap<String, Integer>, this would be
public Integer put(String key, Integer value)
As you can see, the method itself is expecting two arguments. Since you want to pass this as a method reference, it also needs the HashMap<String, Integer> in addition to the two arguments.
BiConsumer<HashMap<String, Integer>, Integer> b1 = HashMap<String, Integer>::put;
Over here, you've correctly marked the first generic type argument as HashMap<String, Integer>, but you're missing the String argument which the put method needs. Unfortunately, there is no TriConsumer, but you can easily define your own interface for it:
@FunctionalInterface
public interface TriConsumer<T, U, V> {
void accept(T t, U u, V v);
}
The @FunctionalInterface annotation is not needed, but it communicates the intent to the reader that this interface can be used as an assignment target for a lambda expression or method reference.
Now you can assign the reference to put:
TriConsumer<HashMap<String, Integer>, String, Integer> consumer = HashMap<String, Integer>::put;
HashMap<String, Integer> map = new HashMap<>();
consumer.accept(map, "Key", 123);
System.out.println(map.get("Key")); // prints 123
2 Comments
The basic problem is that put() is not a typed method - one where the type has method scope and can be inferred, it's a generic instance method - one that takes its type from the type of the instance.
Also, you have a mismatch with the type of the method reference and its generic parameters. I have assumed you meant BiFunction, not BiConsumer.
Let's look at what does work:
HashMap<String, Integer> instance = new HashMap<>();
BiFunction<String, Integer, Integer> b1 = instance::put;
If you really meant BiConsumer, this works too:
BiConsumer<String, Integer> b1 = instance::put;
As I've said, because the method takes its types from the instance, so you need a typed instance.