381 Stimmen

Java 8 Lambdas, Function.identity() or t->t

Ich habe eine Frage zur Verwendung der Methode Function.identity().

Stell dir den folgenden Code vor:

Arrays.asList("a", "b", "c")
          .stream()
          .map(Function.identity()) // <- Das,
          .map(str -> str)          // <- ist das gleiche wie dieses.
          .collect(Collectors.toMap(
                       Function.identity(), // <-- Und das,
                       str -> str));        // <-- ist das gleiche wie dieses.

Gibt es einen Grund, warum man Function.identity() anstelle von str->str (oder umgekehrt) verwenden sollte? Ich denke, dass die zweite Option lesbarer ist (eine Geschmacksfrage natürlich). Aber gibt es einen "echten" Grund, warum man eine bevorzugen sollte?

462voto

Holger Punkte 264693

Zum aktuellen JRE-Setup gibt Function.identity() stets die gleiche Instanz zurück, während jedes Vorkommen von identifier -> identifier nicht nur seine eigene Instanz erstellt, sondern sogar eine eigene Implementierungsklasse hat. Für weitere Details siehe hier.

Der Grund dafür ist, dass der Compiler eine synthetische Methode generiert, die den banalen Körper des Lambda-Ausdrucks enthält (im Fall von x->x, äquivalent zu return identifier;) und zur Laufzeit die Erstellung einer Implementierung des funktionalen Interface aufruft, die diese Methode aufruft. Daher sieht das Laufzeitsystem nur unterschiedliche Zielmethoden, und die aktuelle Implementierung analysiert nicht die Methoden, um festzustellen, ob bestimmte Methoden äquivalent sind.

Die Verwendung von Function.identity() anstelle von x -> x könnte also etwas Speicher sparen, aber das sollte nicht Ihre Entscheidung beeinflussen, wenn Sie wirklich der Meinung sind, dass x -> x lesbarer ist als Function.identity().

Sie sollten auch bedenken, dass beim Kompilieren mit aktivierten Debug-Informationen die synthetische Methode ein Linien-Debug-Attribut haben wird, das auf die Quellcodezeile(n) zeigt, die den Lambda-Ausdruck enthalten. Daher haben Sie die Möglichkeit, die Quelle einer bestimmten Function-Instanz während des Debuggens zu finden. Im Gegensatz dazu, wenn Sie während des Debuggens einer Operation auf die von Function.identity() zurückgegebene Instanz stoßen, werden Sie nicht wissen, wer diese Methode aufgerufen hat und die Instanz an die Operation übergeben hat.

124voto

Pshemo Punkte 118094

In deinem Beispiel besteht kein großer Unterschied zwischen str -> str und Function.identity(), da es intern einfach t->t ist.

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

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

das 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();

wirst du einen Kompilierungsfehler erhalten, da mapToInt ein ToIntFunction erwartet, das nicht mit Function verwandt ist. Auch hat ToIntFunction keine identity() Methode.

54voto

JasonN Punkte 1468

Aus der JDK-Quelle:

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

Also nein, solange es syntaktisch korrekt ist.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X