2017-01-17 3 views
2

Ich habe testen Regeln für die Verwendung von Methodenreferenzen, aber der Code, den ich schrieb, würde nicht kompilieren. Der Compiler sagt mir immer wieder, dass ich aus einem statischen Kontext nicht auf eine nicht statische Methode verweisen kann. In den Java-Dokumenten wurde jedoch explizit geschrieben, dass es möglich ist, "::" zu verwenden, um "auf eine Instanzmethode eines beliebigen Objekts eines bestimmten Typs zu verweisen". Kann jemand darauf hinweisen, was mit meinem Code nicht stimmt? Vielen Dank!Mit Methodenreferenzen für eine Instanz zur Laufzeit in 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: Nachdem die Antworten zu lesen, ich frage mich, ob dies der Fall ist, dass eine Instanz Methode Referenzierung nur durch die Klassennamen in einigen funktionalen Schnittstellen, aber nicht in andere, das funktioniert? Zum Beispiel

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

nicht kompilieren, während:

Predicate <String> predicate = String::isEmpty; 

kompiliert. Wenn dies der Fall ist, gibt es eine Seite/Tutorial/was auch immer, auf die mich jemand verweisen kann, erklärt, welche Funktionsschnittstellen kompatibel sind und welche nicht?

+2

Siehe auch [hier] (http://stackoverflow.com/questions/25512532/lambda-parameters) – Holger

+1

'String :: startsWith' würde 3 Argumente nehmen; 1. die "String" -Instanz, auf die zugegriffen werden soll, 2. der "String" -Parameter "Präfix" und 3. der "int" -Parameter "toffset".Aber ein 'Bipredicate ' kann nur 2 davon berücksichtigen. 'String :: isEmpty', nimmt 1 Parameter, die Instanz, auf der aufgerufen werden soll, so dass ein' Prädikat '_will_ funktioniert. –

+0

@JornVernee Sie sind völlig richtig. Warum ist jedoch Prädikat Prädikat = String :: isEmpty; 'Arbeit? Warum muss ich nicht eine neue Instanz von "String()" übergeben (wie Ihre Antwort unten auf meine ursprüngliche Frage zeigen kann)? –

Antwort

2

Wenn Ihre Methode eine Instanzmethode ist, dann muss man es auf einigen Instanz aufrufen, zum Beispiel:

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

Da Sie keine Instanzvariablen oder Methode verwenden, können Sie es einfach statisch machen und behalte es so wie es ist.

+0

Hat die gleiche Antwort geschrieben;) – JFPicard

+0

Da Methode keine Instanzvariablen/Methoden verwendet, würde ich sagen, dass Ihre Antwort falsch ist, und dass OP einfach die Methode 'static' stattdessen verwenden sollte. Erstellen Sie eine neue Instanz, da der Code in einer nicht statischen Methode vorliegt. Benutze 'this :: evaluate'. – Andreas

2

Wenn eine Instanzmethode statisch referenziert wird, übernimmt der zurückgegebene Funktor ein zusätzliches Argument, das die Instanz darstellt.

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

Aber Sie müssen eine Instanz von Evaluation passieren, wenn es aufgerufen wird.

Da Ihr evaluate Methode keine Instanzfelder verwenden ist, könnte man genauso gut machen es static, dann brauchen Sie keine Instanz zu übergeben, und kann Verwendung nur BiPredicate<Integer, Integer> wie Sie versucht.

+0

'Func biPredicate = Auswertung :: evaluate' Syntaxfehler: * Kann keine statische Referenz auf die nicht-statische Methode evaluate (int, int) vom Typ Evaluation. * Die Einführung einer neuen funktionalen Schnittstelle ändert nichts. – Andreas

+1

@Andreas Versuchen Sie es erneut, ich hatte einen Tippfehler dort. Es funktioniert gut für mich :) –

+0

Wäre es einfacher zu schreiben 'biPredicate = this :: evaluate', anstatt eine neue funktionale Schnittstelle zu erstellen? Oder 'biPredicate = new Evaluation() :: evaluate ', wenn Sie darauf bestehen, ein neues Instanz-Objekt * zu verwenden (obwohl warum?) *? – Andreas

0

Ich bin immer noch die Regel, um herauszufinden, die zutrifft, aber das Problem verschwindet, wenn Sie

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

verwenden ich bin durch https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.13 rätselhaft, aber so nahe, wie ich herausfinden kann, weil die Kräfte Evaluation::evaluate Der Compiler zum Erstellen eines beliebigen Objekts des Typs Evaluation, und Sie rufen es aus einem Objekt dieses Typs, dass die Regel anders ist. Sie müssen es von dem spezifischen Objekt aufrufen, in dem die methodTest-Methode angezeigt wird.

Während ich die Erklärung nicht habe, ist die Lösung zu verwenden. Dies bindet die Methodenreferenz eindeutig an das aufrufende Objekt.

Seitennotiz: Sie müssen boolean nicht als Bedingung auswerten, um eine boolean aus der boolean abzuleiten. Sie könnten einfach return a - b == 5;.

Verwandte Themen