2017-01-17 14 views
2

Я тестировал правила использования ссылок на методы, но код, который я написал, не компилировался. Компилятор продолжает сообщать мне, что я не могу ссылаться на нестатический метод из статического контекста. Однако в Java-документах он явно писал, что можно использовать «::» для «ссылки на метод экземпляра произвольного объекта определенного типа». Кто-нибудь может указать, что не так с моим кодом? Спасибо!Использование ссылок метода на экземпляр, который будет определен во время выполнения в Java

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: После прочтения ответов, мне было интересно, если это тот случай, который ссылается метод экземпляра по имени класса работает только в некоторых функциональных интерфейсах, но не в остальных? Например,

BiPredicate <String, Integer> biPredicate = String::startsWith; 

не компилируется, а:

Predicate <String> predicate = String::isEmpty; 

компилирует. Если это так, есть ли страница/учебник/все, что кто-либо может мне сослаться на это, объясняет, какие функциональные интерфейсы совместимы, а какие нет?

+2

См. Также [здесь] (http://stackoverflow.com/questions/25512532/lambda-parameters) – Holger

+1

'String :: startsWith' будет принимать 3 аргумента; 1. экземпляр «String» для вызова, 2. параметр 'String'' prefix' и 3. параметр 'int'' toffset'.Но 'Bipredicate ' может содержать только 2 из них. 'String :: isEmpty', принимает 1 параметр, экземпляр для вызова, так что' Predicate '_will_ работает. –

+0

@JornVernee Вы совершенно правы. Однако почему 'Predicate предикат = String :: isEmpty; 'работа? Например, почему мне не нужно передавать новый экземпляр 'String()' (Как может быть указано ниже на мой исходный вопрос)? –

ответ

2

Если ваш метод является методом экземпляра, то вы должны вызвать его на каком-то случае, например:

public void methodTest(){ 
    BiPredicate<Integer, Integer> biPredicate = this::evaluate; 
    System.out.println(biPredicate.test(6,1)); 
} 

Поскольку вы не используете переменные экземпляра или метод, вы можете просто сделать его статическим и держи его, как есть.

+0

Написал тот же ответ;) – JFPicard

+0

Поскольку метод не использует переменные/методы экземпляра, я бы сказал, что ваш ответ неверен, и что OP должен просто сделать метод 'static' вместо этого. В качестве альтернативы, поскольку код нестационарный, зачем создавать новый экземпляр? Используйте 'this :: evaluation'. – Andreas

2

При статической ссылке на метод экземпляра возвращаемый функтор принимает дополнительный аргумент, представляющий экземпляр.

interface Func { 
    boolean evaluate(Evaluation instance, int a, int b); 
} 
... 
Func biPredicate = Evaluation::evaluate; 
System.out.println(biPredicate.evaluate(new Evaluation(), 6, 1)); 

Но вам нужно будет пройти экземпляр Evaluation при вызове его.

Поскольку ваш метод evaluate не использует поля экземпляра, вы можете также сделать его static, то вам не нужно передать экземпляр и может использовать только BiPredicate<Integer, Integer> как вы пытались.

+0

'Синтаксическая ошибка Func biPredicate = Evaluation :: оценить': * Невозможно сделать статическую ссылку на оценку нестатического метода (int, int) из типа Evaluation. * Внедрение нового функционального интерфейса ничего не меняет. – Andreas

+1

@Andreas Попробуйте еще раз, у меня была опечатка. Он отлично работает для меня :) –

+0

Было бы проще просто написать «biPredicate = this :: evaluation», а не создавать новый функциональный интерфейс? Или 'biPredicate = new Evaluation() :: оцените', если вы настаиваете на использовании нового экземпляра объекта * (хотя почему?) *? – Andreas

0

Я все еще пытаюсь выяснить, правило, которое применяется, но эта проблема уходит, если вы используете

BiPredicate<Integer, Integer> biPredicate = this::evaluate; 

Я загадочное через https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.13, но так близко, как я могу понять, потому что Evaluation::evaluate сил компилятор для создания произвольного объекта типа Evaluation, и вы вызываете его из объекта такого типа, что правило отличается. Вы должны вызвать его из определенного объекта, внутри которого появляется метод methodTest.

Хотя у меня нет объяснений, решение должно использовать this::evaluate. Это однозначно связывает ссылку метода с вызывающим ее объектом.

Сторона примечания: Вам не нужно оценивать boolean в качестве условного, чтобы получить boolean от boolean. Вы могли бы просто return a - b == 5;.