1

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
samshers
  • 1
  • 6
  • 37
  • 84
  • fine the error messages are not clear and instead confusing.. which lead to the question. Thx for the answers. @Sweeper – samshers Apr 02 '23 at 07:49

2 Answers2

1

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.

user2357112
  • 260,549
  • 28
  • 431
  • 505
  • fine the error messages are not clear and instead confusing.. which lead to the question. Thx for the answer +1 – samshers Apr 02 '23 at 07:50
1

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>.

Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • fine the error messages are not clear and instead confusing.. which lead to the question. Thx for the answers. Accepting+1 – samshers Apr 02 '23 at 07:50
  • the compiler giving error message: `Non-static method cannot be referenced from a static context` is not correct. Right? Seems this is a kind of bug with compiler. – samshers Apr 03 '23 at 01:44
  • @samshers It is possible that this is unintentional, since raw types are very rarely used, and raw functional interfaces even more rarely. They might have overlooked this. Though, also because almost no one uses raw functional interfaces, they probably won't fix it. – Sweeper Apr 03 '23 at 01:47
  • 2
    Java compilers are indeed bad at error analysis/reporting. I [wrote it six years ago](https://stackoverflow.com/a/40174196/2711488); this specific message “Non-static method cannot be referenced from a static context” often occurs when the compiler failed to determine the actual problem. Little has changed in this regard, unfortunately. – Holger Apr 03 '23 at 08:00