2016-05-08 5 views
1

Ich habe 600 Seiten in einen Java-Text und habe etwas Verwirrendes erlebt.Java Lambda Expressions und Event-Info

Im Abschnitt über die Swing-Programmierung werden drei verschiedene Möglichkeiten zum Erstellen eines "EventListener" zum Verarbeiten von Schaltflächenklicks angezeigt. Zuerst wird gezeigt, wie man eine Funktion in einer Klasse verwendet, die ActionListener implementiert, dann wie man eine verschachtelte Klasse verwendet, die ActionListener implementiert, und schließlich wie man einen Lambda-Ausdruck verwendet.

Die ersten beiden Methoden verwenden, um eine im Wesentlichen identische Funktion (Kommentare sind mir):

… 
    button1=new JButton("foobar");    //create a button object 
    button1.addActionListener(this);   //add an event handler to it 
… 
public void actionPerformed(ActionEvent e) { //event handler (standalone or in a class) 
    if (e.getSource() == button1) {   //check if event source is the button 
    //do something 
    } 
} 

Das ist ziemlich einfach ist; Eine Schaltfläche wird erstellt, und entweder das Schaltflächenobjekt selbst oder eine separate Klasse mit einer Funktion wird an addActionListener übergeben, um der Schaltfläche einen Ereignishandler hinzuzufügen.

Das Lambda Expression verwendet eine etwas abgespeckte Funktion, die täuschend ähnlich sieht:

… 
    button1 = new JButton("foobar");    //create a button 
    button1.addActionListener(e -> button1Click()); //set button1Click as event handler 
… 
public void button1Click() {      //event handler 
    //do something 
} 

Was ich verwirrt, ist der Mangel an Ereignisinfo. In den ersten beiden Methoden müssen die Funktionen die Ereignisquelle überprüfen, um zu sehen, ob es die Schaltfläche ist, aber der Lambda-Ausdruck geht davon aus/weiß, dass die Ereignisquelle die Schaltfläche ist. Wie?

Woher kommt das? Der Aufruf an addActionListener beginnt mit button1, aber es wird nirgends in der Lambda-Expression erwähnt. Bedeutet dies nicht, dass die Verwendung eines Lambda-Ausdrucks einschränkt, welche Informationen verfügbar sind? Es gibt keinen Hinweis auf e in der Funktion, so hätte es keine Möglichkeit, die Funktionen für den Zugriff auf Dinge, um herauszufinden, wie der Schlüssel, Zeitstempel usw.



(Oh, und warum Java nennt es ein Ereignis Zuhörer anstelle eines Handler wie fast jede andere Sprache ist mir schleierhaft. und sie sagen, dass Java und JavaScript in Namen ähnlich sind nur ...)

+0

Sie fügen die Lamba zu einem einzigen JButton hinzu, ähnlich wie in einer anonymen inneren Klasse. Wenn Sie dies tun, müssen Sie die Quelle der Schaltfläche nicht überprüfen. Wenn Sie andererseits ein Lambda erstellt und dasselbe einzelne Lambda in mehrere Schaltflächen übertragen haben, dann möchten Sie das ActionEvent hier in die Methode button1Click übergeben: –

+0

'e -> button1Click (e)'. Dann würde die button1Click-Methode natürlich einen ActionEvent-Parameter erfordern, und Sie könnten 'getSource()' darauf aufrufen. –

Antwort

1

Beachten sie, dass die in den nicht-Lambda Fällen bestanden Hörer ist this das heißt, das Objekt, das die Schaltfläche einrichtet. Vermutlich kann dieses Objekt (irgendein Controller oder Container) als Ereignis-Listener für mehrere Schaltflächen dienen, so dass unterschieden werden muss, welche das Ereignis gesendet hat. Das Lambda hingegen erstellt eine einmalige Handler-Instanz, die nur an diese einzelne Schaltfläche angehängt ist, so dass es keine Mehrdeutigkeit gibt.

+0

Das ist, was ich angenommen habe, aber ich kann nicht herausfinden, wo der Zeiger (aus Mangel an einem besseren Begriff) auf die Schaltfläche Objekt kommt. Bei der ersten Methode kann ich sehen, dass sie wegen des 'this' verwendet wird, aber im Lambda (und sogar in der inneren Klasse, die ich jetzt anschaue), gibt es keinen Verweis auf das Schaltflächenobjekt. Ich kann nur annehmen, dass dies alles automatisch hinter den Kulissen geschieht (was für den GC nett ist, aber nur zu Verwirrung führt). – Synetech

+0

@Synetech Das ist nur grundlegende Java; Der Verweis auf den * Button * kommt von 'new JButton'. Dann rufen Sie eine Methode für diese Schaltfläche auf und übergeben ein Objekt, das ein Ereignis-Listener ist. Mit dem Lambda wird das Listener-Objekt nur einmal verwendet; Andernfalls könnte es für mehrere Schaltflächen wiederverwendet werden. – chrylis

1

Sie erwähnen im Lambda-Ausdruck einen "Mangel an Ereignisinformationen". Die Ereignisinformation ist dort im Lambda-Ausdruck - es wird einfach nicht benutzt, wie es in dem anderen Beispiel ist.

Der Ausdruck in diesem Zusammenhang ist

e -> button1Click() 

Abkürzung für

(ActionEvent e) -> buttonClick() 

so können Sie sehen, dass e die Info-Veranstaltung ist.

Auf der anderen Seite, wenn Sie "Mangel an Ereignis-Info" meinen, "Mangel an Verwendung der Ereignis-Info", ist die Antwort, Sie haben Recht, es scheint falsch zu sein.Die beiden Ansätze sind äquivalent, also um Äpfel mit Äpfeln zu vergleichen, sollte keines der beiden Beispiele die Quelle überprüfen, oder beides sollte.

+0

Durch das Fehlen von Event-Informationen, meine ich 'e' ist nur in der Aufruf von' addEventListener' zu sehen und wird nicht an die Funktion 'button1Click' übergeben (die keine Argumente akzeptiert), so dass es nicht nur die Ereignisquelle sieht, Es scheint auch nicht möglich zu sein, auf andere Ereignisinformationen wie Tastendruck oder Zeitstempel zuzugreifen. – Synetech

+0

@Synetech, die beiden Ansätze sind sehr ähnlich in dem, was sie können. Das Lambda könnte äquivalent zum ersten Beispiel geschrieben worden sein, zum Beispiel "(ActionEvent e) -> {if (e.getSource() == button1) {/ * mach etwas * /}}'. Es macht genau dasselbe mit den gleichen Informationen wie das erste Beispiel. Bei beiden Vorgehensweisen wird der Ereignis-Listener registriert, beide Handler haben Zugriff auf dasselbe übergebene Ereignis und beide haben Sichtbarkeit für dieselben Klassenfelder und Elementfunktionen. Warum dieses spezifische Beispiel anders geschrieben wurde und die Ereignisdaten ignoriert wurden, ist ein anderes Problem. –

Verwandte Themen