Lambda-Ausdruck vs. Methodenreferenz [geschlossen]

114

IntelliJ schlägt mir immer wieder vor, meine Lambda-Ausdrücke durch Methodenreferenzen zu ersetzen.

Gibt es einen objektiven Unterschied zwischen beiden?

Gerard
quelle
4
Nicht wirklich, ich sehe kein Objekt! Es sieht aus wie ein statischer Anruf für mich
Gerard
9
Natürlich! Aber "findest du nicht" auch ... Es ist Geschmackssache, ich war mehr besorgt über mehr technische Aspekte. In der Tat, wie Sie bereits gesagt haben, dass sie gleich sind, ist das eine gute Antwort für mich. Wie auch immer, wie IntelliJ es vorschlägt, denke ich, dass es im Allgemeinen mehr geschätzt wird, eine Methodenreferenz als ein Lambda zu sehen (allerdings nicht für mich).
Gerard
15
Der Code eines Lambda-Ausdrucks wird zu einer synthetischen Methode kompiliert, während Methodenreferenzen ohne funktionieren (Ausnahme: spezielle Konstrukte wie Type[]::new). Die zur Laufzeit generierte anonyme Klasse ist dieselbe. Die JRE macht keinen Unterschied zwischen ihnen. Wenn Sie also eine Methodenreferenz verwenden, sparen Sie eine Methode in Ihrem kompilierten Code. Andererseits können Sie beim schrittweisen Debuggen nicht bei ihnen stehen bleiben
Holger
6
Jetzt wird die Frage geschlossen ... Schade für alle Benutzer wie mich, die den Unterschied zwischen Lambdas und Referenzen nicht kennen, auch wenn es keinen entscheidenden gibt. Ich frage mich auch, warum niemand es gewagt hat, darauf zu antworten? Das ist die richtige Antwort für mich.
Gerard
3
Die Beantwortung einer zwei Jahre alten geschlossenen Frage ist wahrscheinlich eine schlechte Idee, aber für diejenigen, die die Frage tatsächlich lesen, lautet das Tutorial von Oracle ( docs.oracle.com/javase/tutorial/java/javaOO/… ): Methodenreferenzen ... sind kompakte, einfach zu lesende Lambda-Ausdrücke für Methoden, die bereits einen Namen haben.
morgen

Antworten:

185

Lassen Sie mich eine Perspektive geben, warum wir diese Funktion zur Sprache hinzugefügt haben, obwohl dies eindeutig nicht unbedingt erforderlich war (alle Methodenreferenzen können als Lambdas ausgedrückt werden.)

Beachten Sie, dass es keine richtige Antwort gibt . Jeder, der sagt "Verwenden Sie immer eine Methodenreferenz anstelle eines Lambda" oder "Verwenden Sie immer ein Lambda anstelle einer Methodenreferenz", sollte ignoriert werden.

Diese Frage ist im Geiste sehr ähnlich zu "Wann sollte ich eine benannte Klasse gegen eine anonyme Klasse verwenden"? Und die Antwort ist dieselbe: Wenn Sie es besser lesbar finden . Es gibt sicherlich Fälle, die definitiv der eine oder andere sind, aber es gibt eine Menge Grau in der Mitte, und das Urteilsvermögen muss angewendet werden.

Die Theorie hinter den Methodenreferenzen ist einfach: Namen sind wichtig . Wenn eine Methode einen Namen hat, ist es oft (aber nicht immer!) Klarer und lesbarer, auf sie mit Namen zu verweisen, anstatt durch einen zwingenden Code-Beutel, der sich letztendlich nur umdreht und ihn aufruft.

Die Argumente zur Leistung oder zum Zählen von Zeichen sind meistens rote Heringe, und Sie sollten sie ignorieren. Das Ziel ist das Schreiben von Code, der kristallklar ist, was er tut. Sehr oft (aber nicht immer!) Gewinnen Methodenreferenzen für diese Metrik, daher haben wir sie als Option aufgenommen, um sie in diesen Fällen zu verwenden.

Eine wichtige Überlegung darüber, ob Methodenreferenzen die Absicht klarstellen oder verschleiern, ist, ob aus dem Kontext ersichtlich ist, welche Form die dargestellte Funktion hat. In einigen Fällen (z. B. ist map(Person::getLastName)aus dem Kontext ziemlich klar, dass eine Funktion erforderlich ist, die eine Sache einer anderen zuordnet, und in solchen Fällen leuchten Methodenreferenzen. In anderen Fällen muss sich der Leser bei Verwendung einer Methodenreferenz fragen, welche Art von Funktion verwendet wird Dies ist ein Warnsignal dafür, dass ein Lambda möglicherweise besser lesbar ist, auch wenn es länger ist.

Schließlich haben wir festgestellt, dass die meisten Leute sich zunächst von Methodenreferenzen abwenden, weil sie sich noch neuer und seltsamer fühlen als Lambdas, und sie daher zunächst "weniger lesbar" finden, aber im Laufe der Zeit, wenn sie sich an die Syntax gewöhnen, Ändern Sie im Allgemeinen ihr Verhalten und tendieren Sie zu Methodenreferenzen, wenn sie können. Seien Sie sich also bewusst, dass Ihre subjektive anfängliche "weniger lesbare" Reaktion mit ziemlicher Sicherheit einen Aspekt der familiären Voreingenommenheit mit sich bringt, und Sie sollten sich die Möglichkeit geben, sich mit beiden vertraut zu machen, bevor Sie eine stilistische Meinung abgeben.

Brian Goetz
quelle
25
@Gerard Danke, wäre eine bessere Antwort gewesen.
Yassin Hajaj
3
@ Gerard Es hört sich so an, als würde Brian sagen "Nein, gibt es nicht"
dj18
Brian, ich erhalte unterschiedliche Ergebnisse mit einer Methodenreferenz und einem Lambda für dieselbe Methode. Sollten sie nicht austauschbar sein?
mFeinstein
@mFeinstein Für jede Methodenreferenz gibt es ein äquivalentes Lambda (das Sie möglicherweise verwenden oder nicht). Code als Frage posten?
Brian Goetz
Ich möchte, aber ich befürchte, der Code könnte zu groß sein, da es sich um ein Android LiveDatainnerhalb eines handelt Fragment, das ich in ein konvertiert habe, Eventdas durch ein ViewModel... ausgelöst wird, und das unterschiedliche Verhalten tritt auf, wenn Android zum selben zurückkehrt Fragment. .so fällt es mir schwer, es für eine Frage zu vereinfachen
mFeinstein
10

Lange Lambda-Ausdrücke, die aus mehreren Anweisungen bestehen, können die Lesbarkeit Ihres Codes beeinträchtigen. In einem solchen Fall ist es möglicherweise besser, diese Anweisungen in einer Methode zu extrahieren und darauf zu verweisen.

Der andere Grund kann die Wiederverwendbarkeit sein . Anstatt Ihren Lambda-Ausdruck aus wenigen Anweisungen zu kopieren und einzufügen, können Sie eine Methode erstellen und von verschiedenen Stellen Ihres Codes aus aufrufen.

Ovunccetin
quelle
3
Vergleiche: houses.map(House::getName)und houses.map(h -> h.getName()). Das Lambda benötigt zwei Zeichen weniger. Es ist wahr, dass der Typ nicht explizit ist, aber jede IDE würde es Ihnen sagen, und außerdem sollten Lambdas verwendet werden, wenn der Typ offensichtlich ist. Ich stimme Ihnen vielleicht in Bezug auf die Wiederverwendbarkeit zu, aber Lambdas sind genau winzig, sodass sie verkettet werden können, anstatt große spezifische Methoden zu erstellen. In diesem Sinne sind kleine Methoden wiederverwendbarer als große und komplexe Methoden, und aufgrund der Klarheit von Lambdas (und bis zu einem gewissen Grad der Ausführlichkeit) sind sie immer noch leicht zu lesen.
Gerard
11
Ich bin bei Gerald. Die Lesbarkeit leidet tatsächlich, wenn Sie Code verschieben. Sie müssen also zum Code springen, um weiterzulesen, und dann zurückspringen. Sie möchten den gesamten relevanten Code an derselben Stelle haben. Auch Houseist ein sehr gütiges Beispiel; was ist mit ThreeStoryRedBrickHouseWithBlueDoors. Ich bevorzuge Methodenreferenzen für Lambdas mit mehreren Argumenten und manchmal, um zu betonen, dass es sich bei dem Lambda nur um einen einzelnen Methodenaufruf handelt. Mit einer Methodenreferenz kann man weniger falsch machen: Sie können das Argument an der Verwendungsstelle falsch
schreiben
@Gerard Ich bin mit Ihrer ersten Aussage nicht einverstanden. Wenn Sie gut beschreibende Methodennamen verwenden und große Codestapel extrahieren, verbessert das Verschieben von Code die Lesbarkeit. Wenn Sie verschleierte Methodennamen verwenden, stimme ich Ihnen zu.
Torsten