2014-02-17 1 views
68

ich an zu den neuen Funktionen lesen: http://www.javaworld.com/article/2078836/java-se/love-and-hate-for-java-8.htmlJava 8 Lambda-Ausdrücke - was über mehrere Methoden in verschachtelter Klasse

sah ich das folgende Beispiel:

Mit Anonymous Klasse:

button.addActionListener(new ActionListener() { 
    public void actionPerformed(ActionEvent ae) { 
     System.out.println("Action Detected"); 
    } 
}); 

Mit Lambda:

button.addActionListener(e -> { 
    System.out.println("Action Detected"); 
}); 

Was würde mit einem MouseListener jemand tun, wenn sie mehrere Methoden innerhalb der anonymen Klasse, z.B .:

public void mousePressed(MouseEvent e) { 
    saySomething("Mouse pressed; # of clicks: " 
       + e.getClickCount(), e); 
} 

public void mouseReleased(MouseEvent e) { 
    saySomething("Mouse released; # of clicks: " 
       + e.getClickCount(), e); 
} 

... und so weiter umsetzen wollen?

+20

Dann müssen Sie nur anonyme Klassen verwenden. Die Einführung von Lambda macht sie nicht veraltet. Lambdas kann nur mit funktionellen Schnittstellen verwendet werden. –

+1

Die Verwendung von Lambdas als ActionListener-Methode ist sehr seltsam. Woher weißt du, dass du die Methode 'actionPerformed' der Schnittstelle' ActionListener' implementierst ?! – bobbel

+2

@bobbel Das ist das ganze Konzept der funktionalen Schnittstellen, ich schlage vor, Sie auf sie zu lesen, bevor Sie sie kommentieren. – skiwi

Antwort

73

Von JLS 9.8

Eine funktionale Schnittstelle ist eine Schnittstelle, die nur eine abstrakte Methode hat und somit stellt eine einzige Funktion Vertrag.

Lambdas benötigen diese funktionalen Schnittstellen und sind daher auf ihre einzige Methode beschränkt. Anonyme Schnittstellen müssen weiterhin zum Implementieren von Schnittstellen mit mehreren Methoden verwendet werden.

addMouseListener(new MouseAdapter() { 

    @Override 
    public void mouseReleased(MouseEvent e) { 
     ... 
    } 

    @Override 
    public void mousePressed(MouseEvent e) { 
     ... 
    } 
}); 
+6

Die Frage aus dem OP lautete: "Was würde jemand tun ** mit einem MouseListener, wenn er mehrere Methoden innerhalb der anonymen Klasse implementieren möchte, z. B .:" (Hervorhebung meins). Die Antwort, die Sie gegeben haben, war gut, sagt aber einfach, dass Sie keine Interfaces verwenden können, die mehr als eine Methode für die Lambda-Beschreibung enthalten. [Holgers Antwort] (http://stackoverflow.com/a/21851111/4229245) erklärt eine Abhilfe hierfür. Sie erweitern auf Ihre eigene Schnittstelle und stellen Standardwerte für die Methoden bereit, die Sie nicht möchten. Dies lässt einen übrig für Ihr Lambda. ** Es wäre nicht das erste cringeworthy, was die Menschen in Java 8 Code zu sehen sein. ** –

4

Ein Java ActionListener muss nur eine einzige Methode implementieren (actionPerformed(ActionEvent e)). Dies passt gut in die Java 8 function, so Java 8 bietet eine einfache Lambda, um eine ActionListener zu implementieren.

Die MouseAdapter erfordert mindestens zwei Methoden und passt daher nicht als function.

60

Sie können Multi-Method-Schnittstellen mit Lambdas verwenden, indem Sie Hilfsschnittstellen verwenden. Dies funktioniert mit solchen Zuhörer Schnittstellen, an denen die Implementierungen von unerwünschten Methoden trivial sind (das heißt wir können nur das tun, was MouseAdapter bietet auch):

// note the absence of mouseClicked… 
interface ClickedListener extends MouseListener 
{ 
    @Override 
    public default void mouseEntered(MouseEvent e) {} 

    @Override 
    public default void mouseExited(MouseEvent e) {} 

    @Override 
    public default void mousePressed(MouseEvent e) {} 

    @Override 
    public default void mouseReleased(MouseEvent e) {} 
} 

Sie müssen nur einmal eine solche Helfer Schnittstelle definieren.

Jetzt können Sie einen Listener für Click-Ereignisse hinzufügen auf Componentc wie folgt aus:

c.addMouseListener((ClickedListener)(e)->System.out.println("Clicked !")); 
+5

Dies scheint mir rococco Lösung für dieses Problem für MouseListeners zu sein. Ich denke, dass das Anfügen eines anonymen Objekts [der alten Methode] besser funktioniert. Es scheint mir ein Klotz zu sein. – ncmathsadist

+1

@ncmathsadist: Fühlen Sie sich frei, die anonyme innere Klasse Ansatz zu verwenden, wenn Sie möchten. Dies ist nur eine Option. Sie können auch [diese Antwort] (http://stackoverflow.com/a/23373921/2711488) betrachten. Es gibt auch [die anderen dynamischen Hörer Generator] (http://docs.oracle.com/javase/7/docs/api/java/beans/EventHandler.html#create (java.lang.Class,% 20java.lang.Object ,% 20java.lang.String,% 20java.lang.String,% 20java.lang.String)) ... – Holger

+5

Ich glaube, dass diese "Kludis" die akzeptierte Antwort sein sollte. Die Frage aus dem OP lautete eindeutig: "Was würde jemand mit einem MouseListener tun, wenn er mehrere Methoden innerhalb der anonymen Klasse implementieren möchte, z. B .:" (Hervorhebung von mir). Er fragt, wie man Lamdas benutzt, wenn man eine Schnittstelle mit mehr als einer Methode hat. @Holger hat das perfekt beantwortet. Das OP weiß offensichtlich bereits, wie man eine anonyme Klasse auf nicht-funktionale Weise verwendet. –

25

Die Lambda EG dieses Problem befaßt hat. Viele Bibliotheken verwenden funktionale Schnittstellen, obwohl sie Jahre vor der funktionalen Schnittstelle entwickelt wurden. Es kommt jedoch manchmal vor, dass eine Klasse mehrere abstrakte Methoden hat und Sie nur eine davon mit einem Lambda targetieren möchten.

Die offiziell hier empfohlenen Muster ist ab Werk Methoden zu definieren:

static MouseListener clickHandler(Consumer<MouseEvent> c) { return ... } 

Diese können durch die APIs sich direkt erfolgen (diese statische Methoden innerhalb von MouseListener sein könnte) oder externe Hilfsmethoden in einem anderen sein könnte Bibliothek sollten die Betreuer entscheiden, diese Bequemlichkeit nicht anzubieten. Da die Anzahl der Situationen, in denen dies erforderlich war, klein ist und die Problemumgehung so einfach ist, schien es nicht zwingend, die Sprache weiter zu entwickeln, um diesen Eckfall zu retten.

Ein ähnlicher Trick für ThreadLocal verwendet wurde; Siehe die neue statische Fabrikmethode withInitial(Supplier<S>).

(By the way, wenn dieses Problem kommt, ist das Beispiel fast immer MouseListener, die ermutigend, da sie die Menge von Klassen schlagen vor, die freundlich werden mögen, Lambda, aber nicht, ist eigentlich ziemlich klein.

)
+2

Siehe auch [diese Frage] (http://stackoverflow.com/q/25299653/1441122). Es gibt eine Handvoll anderer Schnittstellen mit mehreren Methoden, z. B. "WindowListener", aber nur wenige von ihnen. –

-1

Standardmethoden nicht aus Lambda-Ausdrücke zugegriffen werden. Der folgende Code lässt sich nicht kompilieren:

interface Formula { 
    double calculate(int a); 

    default double sqrt(int a) { 
     return Math.sqrt(a); 
    } 
} 
Formula formula = (a) -> sqrt(a * 100); 

nur mit funktionalen Schnittstelle (Single abstrakte Methode + nur eine beliebige Anzahl von Standardmethoden) arbeiten, so Lambda expresion Arbeit mit nur abstrakte Methode

+0

Sorry, aber ich verstehe nicht, wie das mit der Frage zusammenhängt –

0

Lambda-Ausdrücke passt, wo Funktions Schnittstelle muss genau eine abstrakte Methode Erklärung

Verwandte Themen