Die im Lambda-Ausdruck verwendete Variable sollte endgültig oder effektiv endgültig sein
Wenn ich versuche, calTz
es zu verwenden , wird dieser Fehler angezeigt.
private TimeZone extractCalendarTimeZoneComponent(Calendar cal, TimeZone calTz) {
try {
cal.getComponents().getComponents("VTIMEZONE").forEach(component -> {
VTimeZone v = (VTimeZone) component;
v.getTimeZoneId();
if (calTz == null) {
calTz = TimeZone.getTimeZone(v.getTimeZoneId().getValue());
}
});
} catch (Exception e) {
log.warn("Unable to determine ical timezone", e);
}
return null;
}
calTz
vom Lambda ändern .Antworten:
Eine
final
Variable bedeutet, dass sie nur einmal instanziiert werden kann. In Java können Sie keine nicht endgültigen Variablen sowohl in Lambda als auch in anonymen inneren Klassen verwenden.Sie können Ihren Code mit der alten for-each-Schleife umgestalten:
Auch wenn ich einige Teile dieses Codes nicht verstehe:
v.getTimeZoneId();
ohne seinen Rückgabewert zu verwendencalTz = TimeZone.getTimeZone(v.getTimeZoneId().getValue());
ändern Sie die ursprünglich übergebenecalTz
nicht und verwenden sie in dieser Methode nichtnull
, warum setzen Sie nichtvoid
als Rückgabetyp?Hoffe auch diese Tipps helfen dir, dich zu verbessern.
quelle
Obwohl andere Antworten die Anforderung belegen, erklären sie nicht, warum die Anforderung besteht.
Die JLS erwähnt in §15.27.2 , warum :
Um das Risiko von Fehlern zu verringern, haben sie beschlossen, sicherzustellen, dass erfasste Variablen niemals mutiert werden.
quelle
Von einem Lambda kann man keinen Verweis auf etwas bekommen, das nicht endgültig ist. Sie müssen einen endgültigen Wrapper von außerhalb der Lamda deklarieren, um Ihre Variable zu halten.
Ich habe das endgültige 'Referenz'-Objekt als diesen Wrapper hinzugefügt.
quelle
reference.set(calTz);
oder die Referenz muss mit erstellt werdennew AtomicReference<>(calTz)
, da sonst die als Parameter angegebene Zeitzone ungleich Null verloren geht.Java 8 hat ein neues Konzept namens "Effektiv endgültig". Dies bedeutet, dass eine nicht endgültige lokale Variable, deren Wert sich nach der Initialisierung nie ändert, als „effektiv endgültig“ bezeichnet wird.
Dieses Konzept wurde eingeführt, weil wir vor Java 8 keine nicht endgültige lokale Variable in einer anonymen Klasse verwenden konnten . Wenn Sie Zugriff auf eine lokale Variable in einer anonymen Klasse haben möchten , müssen Sie diese endgültig festlegen.
Mit der Einführung von Lambda wurde diese Einschränkung gelockert. Daher ist die Notwendigkeit, die lokale Variable endgültig zu machen, wenn sie nach der Initialisierung als Lambda an sich nicht geändert wird, nichts anderes als eine anonyme Klasse.
Java 8 erkannte den Schmerz, jedes Mal, wenn ein Entwickler Lambda verwendete, lokale Variablen als endgültig zu deklarieren, führte dieses Konzept ein und machte es unnötig, lokale Variablen endgültig zu machen. Wenn Sie also sehen, dass sich die Regel für anonyme Klassen nicht geändert hat, müssen Sie das
final
Schlüsselwort nicht jedes Mal schreiben, wenn Sie Lambdas verwenden.Ich habe hier eine gute Erklärung gefunden
quelle
effectively final
ist kein Code, sondern eine Terminologie. Siehe Wann sollte die Code-Formatierung für Nicht-Code-Text verwendet werden? auf Meta Stack Overflow .final
Schlüsselwort" ist also ein Codewort, dessen Formatierung korrekt ist. Wenn Sie jedoch "final" beschreibend und nicht als Code verwenden, wird stattdessen die Terminologie verwendet.)In Ihrem Beispiel können Sie das
forEach
durch lamdba durch eine einfachefor
Schleife ersetzen und jede Variable frei ändern. Oder überarbeiten Sie Ihren Code wahrscheinlich so, dass Sie keine Variablen ändern müssen. Der Vollständigkeit halber erkläre ich jedoch, was der Fehler bedeutet und wie man ihn umgeht.Java 8-Sprachspezifikation, §15.27.2 :
Grundsätzlich können Sie eine lokale Variable (
calTz
in diesem Fall) nicht innerhalb eines Lambda (oder einer lokalen / anonymen Klasse) ändern . Um dies in Java zu erreichen, müssen Sie ein veränderbares Objekt verwenden und es (über eine letzte Variable) aus dem Lambda ändern. Ein Beispiel für ein veränderliches Objekt wäre hier ein Array aus einem Element:quelle
Wenn es nicht erforderlich ist, die Variable zu ändern, besteht eine allgemeine Problemumgehung für diese Art von Problem darin, den Teil des Codes zu extrahieren, der Lambda verwendet, und das Schlüsselwort final für method-parameter zu verwenden.
quelle
Eine im Lambda-Ausdruck verwendete Variable sollte endgültig oder effektiv endgültig sein. Sie können jedoch einem endgültigen Array mit einem Element einen Wert zuweisen.
quelle