[JAVA] Welches ist schneller, Methodenreferenz oder Lambda-Ausdruck

Einführung

Ich sehe oft Code wie diesen:

employees.stream().map(e -> e.getName()).collect(Collectors.toList());

Code, der eine Liste mit allen Elementen der Liste "Mitarbeiter" erstellt, die in Namen übersetzt werden. Es ist ein normaler Code, aber da der Lambda-Typ wie eine innere Klasse ist, gibt es keinen Overhead? Wenn Sie nur so einen Getter nennen

employees.stream().map(Employee::getName).collect(Collectors.toList());

Ist es nicht schneller?

Ich dachte, ich habe es gemessen, um sicherzugehen. (Obwohl es etwas alt ist, wurde es mit Oracle JDK 1.8u131 gemessen.)

Methodenreferenz oder Lambda-Ausdruck

Benchmark

Mit JMH habe ich die Anzahl der Ausführungen (Durchsatz) jedes Codes pro Sekunde gemessen.

public class PerformanceMethods {
    /**Generieren Sie 10000 Elemente*/
    private static final List<Employee> employees = IntStream.range(0, 10000)
            .mapToObj(i -> new Employee(i, "name" + i))
            .collect(Collectors.toList());

    @Benchmark
    public void useReference() {
        employees.stream().map(Employee::getName).collect(Collectors.toList());
    }

    @Benchmark
    public void useLambda() {
        employees.stream().map(e -> e.getName()).collect(Collectors.toList());
    }
}

Ergebnis ist ···

Benchmark                         Mode  Cnt     Score     Error  Units
PerformanceMethods.useLambda     thrpt    5  5842.820 ±  65.662  ops/s
PerformanceMethods.useReference  thrpt    5  5762.353 ± 343.302  ops/s

Je höher der Score, desto schneller die Verarbeitungsgeschwindigkeit, aber das Ergebnis ist fast das gleiche. Wenn Sie es wiederholt ausführen, spielt es keine Rolle, welches Sie verwenden.

Übrigens werde ich als Referenz ein Dokument veröffentlichen, das den Mechanismus der Ausführung von Lambda-Ausdrücken beschreibt. https://www.slideshare.net/miyakawataku/lambda-meets-invokedynamic

Normalerweise generiert das Erstellen einer inneren Klasse zur Kompilierungszeit eine Klassendatei (Klasse mit "$"), aber Lambda-Ausdrücke werden zur Laufzeit initialisiert, sodass sie schneller zu starten scheint. Im Gegenteil, nur der erste Zeitpunkt, zu dem der Lambda-Ausdruck ausgeführt wird, wird um den Initialisierungsbetrag verzögert.

Ich glaube nicht, dass es mich stört, aber ich persönlich würde gerne eine saubere Methodenreferenz verwenden.

Lambda-Typ einmal oder Karte zweimal

Als ich den von anderen erstellten Code überprüfte, sah ich diesen Code.

employees.stream().map(Employee::getAddress).map(Address::getPostalCode).collect(Collectors.toList());

Zum ersten Mal habe ich gesehen, wie man beim Erstellen einer Werteliste für verschachtelte Entitäten zweimal "map" zum Konvertieren verwendet. ..

Sicher, ich schrieb, dass "ich persönlich eine saubere Methodenreferenz verwenden möchte", aber es scheint, dass "map" zweimal ineffizient ist ...?

Also habe ich die Leistung gemessen, wenn ich "map" einmal mit einem Lambda-Ausdruck und zweimal "map" mit der Methodenreferenz geschrieben habe.

Benchmark

public class PerformanceMethods {
    private static final List<Employee> employees = IntStream.range(0, 10000)
            .mapToObj(i -> new Employee(i, "name" + i, new Address("code" + i)))
            .collect(Collectors.toList());

    @Benchmark
    public void mapOnce() {
        employees.stream()
                 .map(e -> e.getAddress().getCode())
                 .collect(Collectors.toList());
    }

    @Benchmark
    public void mapTwice() {
        employees.stream()
                 .map(Employee::getAddress)
                 .map(Address::getCode)
                 .collect(Collectors.toList());
    }
}

Ergebnis ist ···

Benchmark                     Mode  Cnt     Score      Error  Units
PerformanceMethods.mapOnce   thrpt    5  6340.454 ± 1291.055  ops/s
PerformanceMethods.mapTwice  thrpt    5  5487.546 ±  488.373  ops/s

Ich bin neugierig, dass der Fehlerbereich (Variation der Verarbeitungszeit) für den Lambda-Ausdruck (mapOnce) größer ist, aber ich habe festgestellt, dass map einmal noch schneller ist.

map Es ist einfacher zu verstehen, wenn Sie den Lambda-Ausdruck einmal schreiben. ..

Fazit

Recommended Posts

Welches ist schneller, Methodenreferenz oder Lambda-Ausdruck
Was ist schneller, Array # Sample oder Random # Rand?
Was ist ein Lambda-Ausdruck?
Java: Das Problem ist schneller, Stream oder Loop
Was ist ein Lambda-Ausdruck (Java)
Was ist schneller, Größe oder 0, als Argument von List # toArray?
Java8-Methodenreferenz
[Java] Lambda-Ausdruck
Java8-Methodenreferenz
Java Lambda Ausdruck
Was ist besser, Kotlin oder zukünftiges Java?
Überdenken des Java8-Lambda-Ausdrucks- und Stream-Entwurfsmusters - Muster der Vorlagenmethode -