Zmienna używana w wyrażeniu lambda powinna być ostateczna lub faktycznie ostateczna
Kiedy próbuję użyć calTz
, pokazuje ten błąd.
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
z lambda.Odpowiedzi:
A
final
zmienne oznacza, że może być instancja tylko jeden raz. w Javie nie można używać zmiennych innych niż końcowe w lambdzie ani w anonimowych klasach wewnętrznych.Możesz refaktoryzować swój kod za pomocą starej pętli for-each:
Nawet jeśli nie rozumiem niektórych fragmentów tego kodu:
v.getTimeZoneId();
bez używania wartości zwracanejcalTz = TimeZone.getTimeZone(v.getTimeZoneId().getValue());
nie modyfikujesz pierwotnie przekazanegocalTz
i nie używasz go w tej metodzienull
, dlaczego nie ustawiszvoid
jako typu powrotu?Mam nadzieję, że te wskazówki pomogą Ci poprawić.
źródło
Chociaż inne odpowiedzi potwierdzają ten wymóg, nie wyjaśniają, dlaczego to wymaganie istnieje.
JLS wspomina, dlaczego w §15.27.2 :
Aby zmniejszyć ryzyko błędów, postanowili zapewnić, że przechwycone zmienne nigdy nie będą mutowane.
źródło
Z lambdy nie można uzyskać odniesienia do niczego, co nie jest ostateczne. Musisz zadeklarować końcowe opakowanie spoza lamdy, aby przechowywać zmienną.
Dodałem ostatni obiekt „referencyjny” jako opakowanie.
źródło
reference.set(calTz);
lub odwołanie musi zostać utworzone przy użyciunew AtomicReference<>(calTz)
, w przeciwnym razie niezerowa strefa czasowa podana jako parametr zostanie utracona.Java 8 ma nową koncepcję zwaną zmienną „Efektywnie ostateczna”. Oznacza to, że nieostateczna zmienna lokalna, której wartość nigdy się nie zmienia po inicjalizacji, nazywana jest „Efektywnie końcową”.
Ta koncepcja została wprowadzona, ponieważ przed wersją Java 8 nie mogliśmy używać nieostatecznej zmiennej lokalnej w klasie anonimowej . Jeśli chcesz mieć dostęp do zmiennej lokalnej w klasie anonimowej , musisz to zrobić.
Wraz z wprowadzeniem lambdy to ograniczenie zostało złagodzone. Stąd potrzeba, aby zmienna lokalna była ostateczna, jeśli nie zostanie zmieniona po zainicjowaniu, ponieważ lambda sama w sobie jest niczym innym jak klasą anonimową.
Java 8 zdała sobie sprawę z bólu deklarowania zmiennej lokalnej jako końcowej za każdym razem, gdy programista użył lambdy, wprowadziła tę koncepcję i sprawiła, że nie było potrzeby, aby zmienne lokalne były ostateczne. Więc jeśli widzisz, że reguła dla klas anonimowych się nie zmieniła, to po prostu nie musisz wpisywać
final
słowa kluczowego za każdym razem, gdy używasz lambd.Znalazłem dobre wyjaśnienie tutaj
źródło
effectively final
to nie kod, to terminologia. Zobacz Kiedy należy używać formatowania kodu w przypadku tekstu niekodowego? na Meta Stack Overflow .final
słowo kluczowe” jest słowem kodu, które można sformatować w ten sposób, ale kiedy używa się terminu „final” raczej opisowo niż jako kod, jest to terminologia).W twoim przykładzie możesz zastąpić
forEach
lamdba prostąfor
pętlą i dowolnie modyfikować dowolną zmienną. Lub prawdopodobnie zrefaktoryzuj swój kod, aby nie trzeba było modyfikować żadnych zmiennych. Jednak wyjaśnię dla kompletności, co oznacza błąd i jak go obejść.Specyfikacja języka Java 8, §15.27.2 :
Zasadniczo nie można modyfikować zmiennej lokalnej (
calTz
w tym przypadku) z poziomu lambda (lub klasy lokalnej / anonimowej). Aby to osiągnąć w Javie, musisz użyć mutowalnego obiektu i zmodyfikować go (poprzez końcową zmienną) z lambda. Przykładem modyfikowalnego obiektu byłaby tutaj tablica jednego elementu:źródło
jeśli modyfikacja zmiennej nie jest konieczna, ogólnym obejściem tego rodzaju problemu byłoby wyodrębnienie części kodu, która używa lambda i użycie słowa kluczowego final w metodzie-parametrze.
źródło
Zmienna używana w wyrażeniu lambda powinna być ostateczną lub faktycznie ostateczną, ale można przypisać wartość do końcowej tablicy jednoelementowej.
źródło