Assigning method references to Functional Interfaces

235 Views Asked by At

Java 8+ allows assigning method references to Functional Interfaces.

Then what is the problem with below code (jdoodle link) -

public void newMethod(){
    
    Predicate p = String::isBlank;
    
}

Different from the error in jdoodle compilation, in my local (gist link) i get error:

Non-static method cannot be referenced from a static context

But - below thing worked

 Predicate<String> pp = String::isBlank; //this thing works
2

There are 2 best solutions below

4
Sweeper On BEST ANSWER

This is because you are using a raw type - Predicate. The function type of a raw functional interface is:

The function type of the raw type of a generic functional interface I<...> is the erasure of the function type of the generic functional interface I<...>.

The function type for the generic Predicate<T> is (T) -> boolean (pardon my own original syntax here), a function that takes in a T and returns a boolean. Therefore, the function type of the raw Predicate is (Object) -> boolean, the erasure of (T) -> boolean.

This means that it is possible to assign Objects::isNull to such a raw functional interface (but you shouldn't use raw types in the first place):

// Objects::isNull takes an Object and returns a boolean, so this compiles
Predicate x = Objects::isNull;

The method reference String::blank only takes a String, not any kind of Object. Therefore it is not congruent with the the function type (Object) -> boolean and hence cannot be assigned to a variable of type Predicate.

If Predicate p = String::isBlank; had worked, then you would be able to do something like p.test(1). And String::isBlank would have to magically determine whether 1 "is blank".

The error message here is admittedly a bit confusing.

For Predicate<String>, the definition of its function type is different, and it has the function type (String) -> boolean, which the method reference String::isBlank is congruent to.

The function type of a parameterized functional interface type I<A1...An>, where A1...An are types and the corresponding type parameters of I are P1...Pn, is derived by applying the substitution [P1:=A1, ..., Pn:=An] to the function type of the generic functional interface I<P1...Pn>.

1
user2357112 On

Predicate p doesn't mean "infer the type parameters". It means you've declared a raw Predicate, which operates on an Object.

String::isBlank operates on a String. It can be used for a Predicate<String>, but not a raw Predicate.