Reputation: 310
I was testing out rules of using method references, but the code I wrote would not compile. The compiler keeps giving telling me that I cannot reference a non-static method from a static context. However, in the Java Documents it explicitly wrote that it is possible to use "::" to "reference to an instance method of an arbitrary object of a particular type". Can anyone point out what's wrong with my code? Thank you!
package Test;
import java.util.function.BiPredicate;
class Evaluation {
public boolean evaluate(int a, int b) {
if (a-b ==5){
return true ;
}
return false;
}
public void methodTest() {
BiPredicate<Integer, Integer> biPredicate = Evaluation::evaluate;
System.out.println(biPredicate.test(6,1));
}
}
Edit: After reading the answers, I was wondering if it is the case that referencing an instance method by the class name only works in some functional interfaces but not in other ones? For instance,
BiPredicate <String, Integer> biPredicate = String::startsWith;
doesn't compile, while:
Predicate <String> predicate = String::isEmpty;
compiles. If this is the case, is there a page/tutorial/whatever that anyone can refer me to that explains which function interfaces are compatible and which are not?
Upvotes: 2
Views: 839
Reputation: 948
I am probably way too late to answer this, but since the question is still unanswered I would like to attempt an answer.
I think there is a miss in what OP is trying to achieve.
I understand that OP is trying to understand, why something like this would work:
String str = "abc";
Predicate<String> methodRef = str::startsWith;
methodRef.test("s");
and then,
Predicate <String> predicate = String::isEmpty
Works and in similar fashion, why wouldn't
Predicate <String> predicate = String::startsWith;
Compile which is taking String class name compile.
That is simply because, Predicate basically, takes any argument and returns a boolean. This is not a correct setup for this problem.
You can instead try,
BiFunction<String, String, Boolean> methodRef2 = String::startsWith;
methodRef2.apply("sdsdfsd", "sdfsdf");
This would work, as startswith needs a source string, string to check and return value. Basically there are 4 ways to invoke method references in Java 8
Upvotes: 0
Reputation: 3433
I'm still trying to figure out the rule that applies, but the problem goes away if you use
BiPredicate<Integer, Integer> biPredicate = this::evaluate;
I'm puzzling through https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.13 but as near as I can figure, because the Evaluation::evaluate
forces the compiler to create an arbitrary object of the type Evaluation
, and you're calling it from within an object of that type, that the rule is different. You need to call it from the specific object inside of which the methodTest
method appears.
While I don't have the explanation, the solution is to use this::evaluate
. That unambiguously ties the method reference to the object calling it.
Side note: You don't need to evaluate a boolean
as a conditional in order to derive a boolean
from the boolean
. You could just return a - b == 5;
.
Upvotes: 0
Reputation: 8168
If your method is an instance method, then you have to invoke it on some instance, for example:
public void methodTest(){
BiPredicate<Integer, Integer> biPredicate = this::evaluate;
System.out.println(biPredicate.test(6,1));
}
Since you are not using any instance variables or method, you can simply make it static and keep it like it is.
Upvotes: 2
Reputation: 33875
When statically referencing an instance method, the returned functor takes an additional argument that represents the instance.
interface Func {
boolean evaluate(Evaluation instance, int a, int b);
}
...
Func biPredicate = Evaluation::evaluate;
System.out.println(biPredicate.evaluate(new Evaluation(), 6, 1));
But you will need to pass an instance of Evaluation
when calling it.
Since your evaluate
method does not use any instance fields, you might as well make it static
, then you don't need to pass an instance, and can use just a BiPredicate<Integer, Integer>
like you tried to.
Upvotes: 2