2017-03-05 5 views
5

Ich versuche, eine Arbeitswarteschlange Klasse (FooQueue), die hat zu erstellen:vorbei und eine Member-Funktion in Java Durchsetzung

  • eine Reihe von Funktionsmitgliedern Arbeit tun (do *). Jeder von ihnen nimmt einen Parameter vom selben Typ (FooItem).
  • eine 'add' -Funktion, die 2 Parameter akzeptiert: eine der oben genannten Funktionen und ein FooItem. Am wichtigsten ist, sollte die Add-Funktion nur in der Lage sein, in einer Memberfunktion der FooQueue Klasse zu nehmen, anstatt eine Member-Funktion einer anderen Klasse mit der ähnlichen Signatur

Der Code kompiliert, wenn die tut Funktion statisch ist, sondern nicht wenn die Funktion nicht statisch ist, obwohl die Definition des Instanzfunktionsmembers gemäß this korrekt ist.

Was sollte geändert werden, damit es kompiliert/ausgeführt wird?

public class App { 
    public static void main(String[] args) { 
     FooQueue q = new FooQueue(); 
     q.add(FooQueue::dos, new FooItem()); // this compiles 
     q.add(q::do1, new FooItem());   // this does not: 
                // does not consider q::do1 'delegate' 
                // as taking 2 parameters, 
                // with q being the first one 
     FooQueue q2 = new FooQueue2(); 
     q.add(FooQueue2::dos, new FooItem()); // want this to give compiler error 
     q.add(FooQueue2::do1, new FooItem()); // want this to give compiler error 
    } 
} 

public class FooQueue { 
    public static void dos(FooQueue q, FooItem item) { 
     System.out.println("FooQueue:sdo"); 
    } 
    public void do1(FooItem item) { 
     System.out.println("FooQueue:do1"); 
    } 
    public void add(java.util.function.BiConsumer<FooQueue,FooItem> func, FooItem wi) { 
     System.out.println("FooQueue:addWorkItem2"); 
     func.accept(this, wi); 
    } 
} 
public class FooItem { 
} 
public class FooQueue2 { 
    public static void dos(FooQueue2 q2, FooItem item) { 
     System.out.println("FooQueue2:sdo"); 
    } 
    public void do1(FooItem item) { 
     System.out.println("FooQueue2:do1"); 
    } 
} 

Antwort

7

Es ist nicht zu statisch/nicht-statische Methode, noch Generika, sondern nur auf BiConsumer Definition verwendet.

BiConsumer erfordert zwei Parameter, Sie benötigen also Lambda, das zwei Parameter benötigt und keine zurückgibt.

Um das zu beheben, verwenden Sie Instanz-Methode Referenz:

FooQueue q = new FooQueue(); 
q.add(FooQueue::do1, new FooItem()); 

Nicht verwechseln mit statischer Methode Referenz. FooQueue::do1 ist syntaktischer Zucker für Lambda:

(qInstance, item) -> qInstance.do1(item)); 

Dieser Ansatz ermöglicht es Ihnen, nur Methoden von FooQueue zu akzeptieren.

Beachten Sie, dass q:do1 mit BiConsumer nicht kompatibel ist, wie es umgesetzt hat:

(item) -> q.do1(item) 

Lesen Sie mehr über Instance method reference


Voll Beispiel mit verschiedenen Klassen

public class App { 
    public static void main(String[] args) { 
     FooQueue q = new FooQueue(); 
     FooQueue2 q2 = new FooQueue2(); 

     q.add(FooQueue::do1, new FooItem()); 
     // Equals to: 
     q.add((qInstance, item) -> qInstance.do1(item), new FooItem()); 

     // q.add(FooQueue2::do1, new FooItem()); // not compile 
    } 
} 

class FooQueue { 
    void do1(FooItem item) { 
     System.out.println("FooQueue:do1"); 
    } 

    void add(BiConsumer<FooQueue, FooItem> func, FooItem wi) { 
     System.out.println("FooQueue:addWorkItem"); 
     func.accept(this, wi); 
    } 
} 

// class that pretends to be FooQueue 
class FooQueue2 { 
    void do1(FooItem item) { 
     System.out.println("FooQueue2:do1"); 
    } 
} 

class FooItem { 
} 
+3

Thank s. Gibt es eine Möglichkeit, FooQueue :: zu erzwingen, nur FooQueue Mitgliedsfunktionen (zur Kompilierzeit) akzeptieren? Leider Consumer erzwingen die Parameter, aber nicht die Klassenzugehörigkeit, die das Stammproblem ist, das ich gerne lösen würde. – daniel

+2

@daniel Jetzt verstehe ich besser das Problem, das du lösen willst. Ich habe meine Antwort mit einem geeigneten Beispiel umgeschrieben. Lass es mich wissen, wenn das hilft. –

Verwandte Themen