람다 식에 사용되는 변수는 최종적이거나 사실상 최종적이어야합니다.
람다 식에 사용되는 변수는 최종적이거나 사실상 최종적이어야합니다.
사용하려고 할 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;
}
final
변수 수단은 한 번만 인스턴스화 될 수있다. Java에서는 람다와 익명의 내부 클래스에서 최종 변수가 아닌 변수를 사용할 수 없습니다.
이전 for-each 루프를 사용하여 코드를 리팩터링 할 수 있습니다.
private TimeZone extractCalendarTimeZoneComponent(Calendar cal,TimeZone calTz) {
try {
for(Component component : cal.getComponents().getComponents("VTIMEZONE")) {
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;
}
이 코드의 일부를 이해하지 못하더라도 :
v.getTimeZoneId();
반환 값을 사용하지 않고 a를 호출 합니다.- 할당
calTz = TimeZone.getTimeZone(v.getTimeZoneId().getValue());
을calTz
사용하면 원래 전달 된 내용을 수정하지 않고이 방법에서 사용하지 않습니다. - 당신은 항상 반환합니다
null
. 왜void
반환 유형으로 설정하지 않습니까?
이 팁이 개선에 도움이되기를 바랍니다.
다른 답변이 요구 사항을 증명하지만 요구 사항이 존재 하는 이유를 설명하지 않습니다 .
JLS는 §15.27.2 에서 이유를 언급합니다 .
효과적인 최종 변수에 대한 제한은 동적으로 변경되는 지역 변수에 대한 액세스를 금지하며, 캡처시 동시성 문제가 발생할 가능성이 있습니다.
버그 위험을 낮추기 위해 그들은 캡처 된 변수가 절대 변하지 않도록하기로 결정했습니다.
람다에서 최종적이지 않은 것에 대한 참조를 얻을 수 없습니다. 변수를 보유하려면 람다 외부에서 최종 래퍼를 선언해야합니다.
이 래퍼로 최종 '참조'개체를 추가했습니다.
private TimeZone extractCalendarTimeZoneComponent(Calendar cal,TimeZone calTz) {
final AtomicReference<TimeZone> reference = new AtomicReference<>();
try {
cal.getComponents().getComponents("VTIMEZONE").forEach(component->{
VTimeZone v = (VTimeZone) component;
v.getTimeZoneId();
if(reference.get()==null) {
reference.set(TimeZone.getTimeZone(v.getTimeZoneId().getValue()));
}
});
} catch (Exception e) {
//log.warn("Unable to determine ical timezone", e);
}
return reference.get();
}
Java 8 has a new concept called “Effectively final” variable. It means that a non-final local variable whose value never changes after initialization is called “Effectively Final”.
This concept was introduced because prior to Java 8, we could not use a non-final local variable in an anonymous class
. If you wanna have access to a local variable in anonymous class
, you have to make it final.
When lambda
was introduced, this restriction was eased. Hence to the need to make local variable final
if it’s not changed once it is initialized as lambda in itself is nothing but an anonymous class.
Java 8 realized the pain of declaring local variable final
every time developer used lambda
and introduced this concept and made it unnecessary to make local variables final
. So if you see the rule for anonymous class
still not changed, it’s just you don’t have to write final
keyword every time when using lambdas
.
I found a good explanation here
In your example, you can replace the forEach
with lamdba with a simple for
loop and modify any variable freely. Or, probably, refactor your code so that you don't need to modify any variables. However, I'll explain for completeness what does the error mean and how to work around it.
Java 8 Language Specification, §15.27.2:
Any local variable, formal parameter, or exception parameter used but not declared in a lambda expression must either be declared final or be effectively final (§4.12.4), or a compile-time error occurs where the use is attempted.
Basically you cannot modify a local variable (calTz
in this case) from within a lambda (or a local/anonymous class). To achieve that in Java, you have to use a mutable object and modify it (via a final variable) from the lambda. One example of a mutable object here would be an array of one element:
private TimeZone extractCalendarTimeZoneComponent(Calendar cal, TimeZone calTz) {
TimeZone[] result = { null };
try {
cal.getComponents().getComponents("VTIMEZONE").forEach(component -> {
...
result[0] = ...;
...
}
} catch (Exception e) {
log.warn("Unable to determine ical timezone", e);
}
return result[0];
}
if it is not necessary to modify the variable than a general workaround for this kind of problem would be to extract the part of code which use lambda and use final keyword on method-parameter.
'Programming' 카테고리의 다른 글
Eclipse에서 다른 Android 프로젝트의 Android 라이브러리 프로젝트를 참조 할 수 없습니다. (0) | 2020.08.14 |
---|---|
프로그래밍 방식으로 활동 테마 변경 (0) | 2020.08.14 |
구조체 이니셜 라이저에서 점 (.)은 무엇을 의미합니까? (0) | 2020.08.13 |
RTTI를 사용하는 것보다 '순수한 다형성'이 선호되는 이유는 무엇입니까? (0) | 2020.08.13 |
main ()에서 EXIT_SUCCESS 또는 0을 반환해야합니까? (0) | 2020.08.13 |