wake-up-neo.net

Java8 Lambdas vs anonyme Klassen

Da Java8 kürzlich veröffentlicht wurde und seine brandneuen Lambda-Ausdrücke wirklich cool aussehen, habe ich mich gefragt, ob dies den Abbruch der anonymen Klassen bedeutet, an die wir uns so gewöhnt haben.

Ich habe ein wenig darüber recherchiert und einige coole Beispiele dafür gefunden, wie Lambda-Ausdrücke diese Klassen systematisch ersetzen werden, beispielsweise die Sortiermethode der Collection, mit der eine anonyme Instanz von Comparator für die Sortierung verwendet wurde: 

Collections.sort(personList, new Comparator<Person>(){
  public int compare(Person p1, Person p2){
    return p1.firstName.compareTo(p2.firstName);
  }
});

Jetzt kann mit Lambdas gearbeitet werden: 

Collections.sort(personList, (Person p1, Person p2) -> p1.firstName.compareTo(p2.firstName));

Und sieht überraschend prägnant aus. Meine Frage ist also: Gibt es einen Grund, diese Klassen in Java8 anstelle von Lambdas zu verwenden?

EDIT

Gleiche Frage, aber in umgekehrter Richtung: Welche Vorteile bietet die Verwendung von Lambdas anstelle von Anonymous-Klassen? Da Lambdas nur mit Schnittstellen für einzelne Methoden verwendet werden kann, ist diese neue Funktion nur eine Abkürzung, die nur in wenigen Fällen verwendet wird, oder ist sie wirklich nützlich?

89
Amin Abu-Taleb

Eine anonyme innere Klasse (AIC) kann verwendet werden, um eine Unterklasse einer abstrakten Klasse oder einer konkreten Klasse zu erstellen. Ein AIC kann auch eine konkrete Implementierung einer Schnittstelle bereitstellen, einschließlich des Hinzufügens von Status (Feldern). Auf eine Instanz einer AIC kann in ihren Methodenkörpern mit this verwiesen werden, sodass weitere Methoden aufgerufen werden können, ihr Status im Laufe der Zeit verändert werden kann usw. Keine dieser Methoden trifft auf Lambdas zu.

Ich vermute, dass die meisten AIC-Anwendungen zustandslose Implementierungen einzelner Funktionen zur Verfügung stellen und daher durch Lambda-Ausdrücke ersetzt werden können. Es gibt jedoch auch andere AIC-Anwendungen, für die Lambdas nicht verwendet werden können. AICs sind hier zu bleiben.

UPDATE

Ein weiterer Unterschied zwischen AICs und Lambda-Ausdrücken besteht darin, dass AICs einen neuen Anwendungsbereich einführen. Das heißt, Namen werden von den Oberklassen und Schnittstellen der AIC aufgelöst und können Namen spiegeln, die in der lexzial einschließenden Umgebung vorkommen. Bei Lambdas werden alle Namen lexikalisch aufgelöst.

86
Stuart Marks

Lambdas sind zwar eine großartige Funktion, funktionieren jedoch nur mit SAM-Typen. Das heißt, Schnittstellen nur mit einer einzigen abstrakten Methode. Es würde fehlschlagen, sobald Ihre Schnittstelle mehr als eine abstrakte Methode enthält. Hier werden anonyme Klassen nützlich sein.

Nein, wir können anonyme Klassen nicht einfach ignorieren. Und nur zu Ihrer Information, Ihre sort()-Methode kann vereinfacht werden, indem Sie die Typdeklaration für p1 und p2 überspringen:

Collections.sort(personList, (p1, p2) -> p1.firstName.compareTo(p2.firstName));

Sie können hier auch die Methodenreferenz verwenden. Sie fügen entweder eine compareByFirstName()-Methode in der Person-Klasse hinzu und verwenden:

Collections.sort(personList, Person::compareByFirstName);

oder fügen Sie einen Getter für firstName hinzu, rufen Sie direkt die Comparator aus der Comparator.comparing() -Methode ab:

Collections.sort(personList, Comparator.comparing(Person::getFirstName));
53
Rohit Jain

Lambda-Performance mit anonymen Klassen

Beim Start der Anwendung muss jede Klassendatei geladen und überprüft werden.

Anonyme Klassen werden vom Compiler als neuer Untertyp für die angegebene Klasse oder Schnittstelle verarbeitet, sodass für jede Klasse eine neue Klassendatei generiert wird.

Lambdas unterscheiden sich bei der Bytecode-Generierung, sie sind effizienter und werden mit invokedynamic-Anweisungen verwendet, die mit JDK7 geliefert werden.

Bei Lambdas wird diese Anweisung verwendet, um die Übersetzung des Lambda-Ausdrucks im Bytecode bis zur Laufzeit zu verzögern. (Anweisung wird nur zum ersten Mal aufgerufen)

Als Ergebnis wird der Lambda-Ausdruck zu einer statischen Methode (zur Laufzeit erstellt). (Es gibt einen kleinen Unterschied zwischen Stateles und Statefull-Fällen, sie werden über generierte Methodenargumente aufgelöst)

29
Dmitriy Kuzkin

Es gibt folgende Unterschiede: 

1) Syntax

Lambda-Ausdrücke sehen im Vergleich zu Anonymous Inner Class (AIC) sauber aus

public static void main(String[] args) {
    Runnable r = new Runnable() {
        @Override
        public void run() {
            System.out.println("in run");
        }
    };

    Thread t = new Thread(r);
    t.start(); 
}

//syntax of lambda expression 
public static void main(String[] args) {
    Runnable r = ()->{System.out.println("in run");};
    Thread t = new Thread(r);
    t.start();
}

2) Geltungsbereich

Eine anonyme innere Klasse ist eine Klasse. Dies bedeutet, dass innerhalb der inneren Klasse ein Variablenbereich definiert ist. 

Lambda expression ist zwar kein eigener Bereich, sondern Teil des einschließenden Geltungsbereichs. 

Eine ähnliche Regel gilt für super und this, wenn innerhalb anonymer innerer Klassen und Lambda-Ausdrücke verwendet wird. Im Falle einer anonymen inneren Klasse bezieht sich dieses Schlüsselwort auf den lokalen Bereich und ein Super-Schlüsselwort auf die Superklasse der anonymen Klasse. Im Falle eines Lambda-Ausdrucks bezieht sich dieses Schlüsselwort auf das Objekt des umgebenden Typs und super auf die Oberklasse der umgebenden Klasse.

//AIC
    public static void main(String[] args) {
        final int cnt = 0; 
        Runnable r = new Runnable() {
            @Override
            public void run() {
                int cnt = 5;    
                System.out.println("in run" + cnt);
            }
        };

        Thread t = new Thread(r);
        t.start();
    }

//Lambda
    public static void main(String[] args) {
        final int cnt = 0; 
        Runnable r = ()->{
            int cnt = 5; //compilation error
            System.out.println("in run"+cnt);};
        Thread t = new Thread(r);
        t.start();
    }

3) Leistung

Zur Laufzeit erfordern anonyme innere Klassen das Laden von Klassen, die Speicherzuordnung und die Objektinitialisierung sowie den Aufruf einer nicht statischen Methode, während der Lambda-Ausdruck reine Kompilierungszeit ist und während der Laufzeit keine zusätzlichen Kosten entstehen. Daher ist die Leistung des Lambda-Ausdrucks besser als bei anonymen inneren Klassen. **

** Mir ist klar, dass dieser Punkt nicht ganz richtig ist. Bitte beziehen Sie sich auf die folgende Frage für Details. Lambda vs. anonyme Leistung in der inneren Klasse: Verringerung der Belastung des ClassLoader?

10
atom217

Lambda's in Java 8 wurde zur funktionalen Programmierung eingeführt. Wo Sie Boilerplate-Code vermeiden können. Ich bin auf diesen interessanten Artikel über Lambda gestoßen.

http://radar.oreilly.com/2014/04/whats-new-in-Java-8-lambdas.html

Es ist ratsam, für einfache Logik Lambda-Funktionen zu verwenden. Wenn das Implementieren einer komplexen Logik mit Lambdas im Fehlerfall einen erheblichen Aufwand beim Debuggen des Codes zur Folge hat.

3
Tim
  • für die Lambda-Syntax muss nicht der offensichtliche Code geschrieben werden, den Java ableiten kann.
  • Mit invoke dynamic werden Lambda nicht zurück in die anonymen Klassen konvertiert während der Kompilierzeit (Java muss keine Objekte erstellen, muss sich nur um die Signatur der Methode kümmern, kann sich an die Methode binden, ohne ein Objekt zu erstellen
  • lambda legt mehr Wert darauf, was wir tun wollen, als was wir tun müssen, bevor wir es tun können
0
MagGGG

Vergleichen wir den Unterschied zwischen der Lambda-Expression und der Anonymous-Klasse.

1. Syntax

Anonyme Klasse:

package com.onlyfullstack;
public class LambdaVsAnonymousClass {

 public static void main(String[] args) {
  Runnable runnable = new  Runnable() {
   @Override
   public void run() {
    System.out.println("Anonymous class");
   }
  };

  Thread thread = new Thread(runnable);
  thread.start();
 }
}

Lambda:

package com.onlyfullstack;
public class LambdaVsAnonymousClass {

 public static void main(String[] args) {
  Runnable runnable = () -> System.out.println("Lambda Expression");

  Thread thread = new Thread(runnable);
  thread.start();
 }
}

2. Implementierung

Anonyme Klasse kann verwendet werden, um eine beliebige Schnittstelle mit einer beliebigen Anzahl abstrakter Methoden zu implementierenLambda-Ausdruck funktioniert nur mit SAM-Typen (Single Abstract Method). Das ist eine Schnittstelle mit nur einer einzigen abstrakten Methode, die auch als funktionales Interface bezeichnet wird. Es würde fehlschlagen, sobald Ihre Schnittstelle mehr als eine abstrakte Methode enthält.

3. Zusammenstellung

Anonyme Klasse: Java erstellt zwei Klassendateien für die Java-Datei LambdaVsAnonymousClass als LambdaVsAnonymousClass.class - enthält das Hauptprogramm LambdaVsAnonymousClass $ 1.class - enthält eine anonyme Klasse  enter image description here

Lambda-Ausdruck: Mit Lambda-Ausdruck erstellt der Compiler nur eine Klassendatei wie unten .  Lambda Expression

Java erstellt also die neue Klassendatei für jede verwendete anonyme Klasse.

4. Leistung

Anonyme Klassen werden vom Compiler als neuer Subtyp für die angegebene Klasse oder Schnittstelle verarbeitet, sodass für jede verwendete anonyme Klasse eine neue Klassendatei generiert wird. Beim Start der Anwendung wird jede Klasse, die für die Anonymous-Klasse erstellt wurde, geladen und überprüft. Dieser Vorgang ist ziemlich zeitaufwändig, wenn Sie über eine große Anzahl anonymer Klassen verfügen.

Lambda-Ausdrücke Anstatt direkte Bytecodes für Lambda zu generieren (wie der vorgeschlagene anonyme Klassen-Syntaxzucker), deklariert der Compiler ein Rezept (über invokeDynamic-Anweisungen) und delegiert den realen Konstruktionsansatz an die Laufzeit.

Lambda-Ausdrücke sind also schneller als die anonymen Klassen, da sie nur ausgeführt werden, wenn sie aufgerufen werden.

Weitere Informationen finden Sie unter den folgenden Links: 

https://onlyfullstack.blogspot.com/2019/02/lambda-vs-anonymous-class-in-Java-8.html

https://onlyfullstack.blogspot.com/2019/02/wie-lambda-internally-works-in-Java-8.html

0
Saurabh Oza

Anonyme Klassen sind da, um zu bleiben, weil Lambda für Funktionen mit einzelnen abstrakten Methoden gut ist, aber in allen anderen Fällen sind anonyme innere Klassen Ihr Retter.

0
spidy