Wenn ein Lambda eine Variable erfasst, kann man sich vorstellen, dass das Lambda eine Kopie des Werts dieser Variablen erhält. Da nur finale oder effektiv endgültige Variablen erfasst werden können, ist es für Lambdas sicher, sie zu kopieren. Ihre Werte ändern sich nicht, daher besteht keine Gefahr, dass die Kopie nicht mit der ursprünglichen Variablen übereinstimmt.
Lambdas muss nicht mit anonymen Klassen implementiert werden, aber Sie können sie konzeptionell als syntaktischen Zucker für anonyme Klassen betrachten. Ihr whenComplete
Anruf entspricht:
long startTime = System.currentTimeMillis();
result.whenComplete(new BiConsumer<T, U>() {
@Override public void accept(T res, U err) {
System.out.println(System.currentTimeMillis() - startTime);
}
});
Die Sache ist, ist variabel Capturing mit Lambda-Ausdrücke nicht neu. Anonyme Klassen erfassen auch Variablen, und sie haben es getan, bevor lambdas kam. Was passiert, ist, dass sie heimlich Kopien von erfassten Variablen verstauen. Sie erhalten synthetische private Felder, um diese versteckten Werte zu speichern. Der obige Code ist eigentlich eher wie dieses, wenn wir das synthetische Feld explizit zu machen:
long startTime = System.currentTimeMillis();
result.whenComplete(new BiConsumer<T, U>() {
private final long _startTime = startTime;
@Override public void accept(T res, U err) {
System.out.println(System.currentTimeMillis() - _startTime);
}
});
Beachten Sie, dass, sobald diese anonyme BiConsumer
instanziiert wird es auf eigenen Füßen steht. Der Rumpf von accept()
verweist jetzt auf eine Instanzvariable, nicht auf die erfasste Variable. Das anonyme Objekt ist weder mit der äußeren Funktion noch mit dem Thread verknüpft, in dem es erstellt wurde. accept()
kann jederzeit und von jedem Thread aufgerufen werden und wird sich so verhalten, wie man es erwarten würde, auch wenn die ursprüngliche startTime
Variable längst tot und vergraben ist.
Bitte lesen Sie Ihre Frage erneut und bearbeiten Sie sie. Die Formulierung ist nicht sehr klar. – michaelsnowden