Java 8 lambdas, function.identität () oder t-> t

Ich habe eine Frage bezüglich der Verwendung der Function.identity() -Methode.

Stellen Sie sich den folgenden Code vor:

 Arrays.asList("a", "b", "c") .stream() .map(Function.identity()) //  str) // <- is the same as this. .collect(Collectors.toMap( Function.identity(), //  str)); // <-- is the same as this. 

Gibt es einen Grund, warum Sie Function.identity() anstelle von str->str (oder umgekehrt) verwenden sollten. Ich denke, dass die zweite Option besser lesbar ist (natürlich eine Frage des Geschmacks). Aber gibt es einen “echten” Grund, warum man bevorzugt werden sollte?

Ab der aktuellen JRE-Implementierung gibt Function.identity() immer die gleiche Instanz zurück, während jedes Auftreten von identifier -> identifier nicht nur eine eigene Instanz, sondern auch eine eigene Implementierungsklasse erzeugt. Für weitere Details, siehe hier .

Der Grund dafür ist, dass der Compiler eine synthetische Methode generiert, die den trivialen Körper dieses Lambda-Ausdrucks enthält (im Fall von x->x entspricht der return identifier; ) und die Laufzeit anweist, eine Implementierung der funktionalen Schnittstelle zu erstellen, die diese Methode aufruft. Daher sieht die Laufzeitumgebung nur verschiedene Zielmethoden, und die aktuelle Implementierung analysiert die Methoden nicht, um herauszufinden, ob bestimmte Methoden äquivalent sind.

Wenn Sie also Function.identity() anstelle von x -> x verwenden, können Sie zwar etwas Speicher sparen, aber das sollte Ihre Entscheidung nicht beeinflussen, wenn Sie wirklich denken, dass x -> x besser lesbar ist als Function.identity() .

Sie können auch berücksichtigen, dass die synthetische Methode beim Kompilieren mit aktivierten Debug-Informationen über ein Zeilen-Debug-Attribut verfügt, das auf die Quellcodezeile (n) verweist, die den Lambda-Ausdruck enthalten. Daher haben Sie die Möglichkeit, die Quelle einer bestimmten Function Debuggen. Wenn Sie während des Debuggens einer Operation auf die von Function.identity() Instanz stoßen, wissen Sie dagegen nicht, wer diese Methode aufgerufen und die Instanz an die Operation übergeben hat.

In Ihrem Beispiel gibt es keinen großen Unterschied zwischen str -> str und Function.identity() da intern einfach t->t .

Aber manchmal können wir Function.identity nicht verwenden, da wir keine Function . Schau mal hier:

 List list = new ArrayList<>(); list.add(1); list.add(2); 

Dies wird gut kompilieren

 int[] arrayOK = list.stream().mapToInt(i -> i).toArray(); 

aber wenn du versuchst zu kompilieren

 int[] arrayProblem = list.stream().mapToInt(Function.identity()).toArray(); 

Sie erhalten einen Kompilierungserrors, da mapToInt erwartet, was nicht mit Function . Auch ToIntFunction hat keine identity() -Methode.

Aus der JDK-Quelle :

 static  Function identity() { return t -> t; } 

Also, nein, solange es syntaktisch korrekt ist.