Переменная, используемая в лямбда-выражении, должна быть окончательной или фактически окончательной.
Когда я пытаюсь использовать, calTz
он показывает эту ошибку.
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
лямбда.Ответы:
А
final
переменная означает , что он может быть создан только один раз. в Java нельзя использовать неокончательные переменные в лямбда-выражениях, а также в анонимных внутренних классах.Вы можете реорганизовать свой код с помощью старого цикла for-each:
Даже если я не понимаю некоторых частей этого кода:
v.getTimeZoneId();
без использования его возвращаемого значенияcalTz = TimeZone.getTimeZone(v.getTimeZoneId().getValue());
вы не изменяете первоначально переданноеcalTz
и не используете его в этом методеnull
, почему бы вам не установитьvoid
возвращаемый тип?Надеюсь, эти советы помогут вам стать лучше.
источник
Хотя другие ответы подтверждают наличие требования, они не объясняют, почему это требование существует.
JLS упоминает, почему в §15.27.2 :
Чтобы снизить риск ошибок, они решили гарантировать, что захваченные переменные никогда не мутируют.
источник
Из лямбды вы не можете получить ссылку ни на что не окончательное. Вам нужно объявить финальную оболочку извне lamda для хранения вашей переменной.
Я добавил последний объект «ссылка» в качестве этой оболочки.
источник
reference.set(calTz);
или ссылка должна быть создана с использованиемnew AtomicReference<>(calTz)
, иначе ненулевой часовой пояс, указанный в качестве параметра, будет потерян.В Java 8 появилась новая концепция переменной, которая называется «эффективно конечная». Это означает, что неконечная локальная переменная, значение которой никогда не изменяется после инициализации, называется «Фактически конечной».
Эта концепция была введена потому, что до Java 8 мы не могли использовать неконечную локальную переменную в анонимном классе . Если вы хотите иметь доступ к локальной переменной в анонимном классе , вы должны сделать это окончательным.
Когда была введена лямбда, это ограничение было снято. Следовательно, необходимо сделать локальную переменную окончательной, если она не изменилась после инициализации, поскольку лямбда сама по себе является не чем иным, как анонимным классом.
В Java 8 осознали боль объявления локальной переменной final каждый раз, когда разработчик использовал лямбда, представил эту концепцию и сделал ненужным делать локальные переменные final. Поэтому, если вы видите, что правило для анонимных классов не изменилось, просто вам не нужно
final
каждый раз писать ключевое слово при использовании лямбда-выражений.Я нашел хорошее объяснение здесь
источник
effectively final
это не код, это терминология. См. Раздел Когда следует использовать форматирование кода для текста, не являющегося кодом? о переполнении мета-стека .final
ключевое слово» - это слово кода и его можно правильно отформатировать таким образом, но когда вы используете «final» описательно, а не как код, вместо этого используется терминология).В вашем примере вы можете заменить на
forEach
lamdba простойfor
цикл и свободно изменять любую переменную. Или, возможно, реорганизуйте свой код, чтобы вам не нужно было изменять какие-либо переменные. Однако я объясню для полноты, что означает ошибка и как ее обойти.Спецификация языка Java 8, §15.27.2 :
По сути, вы не можете изменить локальную переменную (
calTz
в этом случае) из лямбда (или локального / анонимного класса). Чтобы добиться этого в Java, вы должны использовать изменяемый объект и изменить его (через конечную переменную) с помощью лямбда. Одним из примеров изменяемого объекта здесь может быть массив из одного элемента:источник
Если нет необходимости изменять переменную, то общий способ решения проблемы такого рода состоит в том, чтобы извлечь часть кода, в которой используется лямбда, и использовать ключевое слово final в параметре метода.
источник
Переменная, используемая в лямбда-выражении, должна быть окончательной или фактически окончательной, но вы можете присвоить значение последнему массиву из одного элемента.
источник