람다 식에 사용되는 변수는 최종 변수이거나 사실상 최종 변수여야 합니다.
람다 식에 사용되는 변수는 최종 변수이거나 사실상 최종 변수여야 합니다.
★★★★★★★★★★★★★★★★★★★를 사용하려고 하면,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;
}
다른 답변은 요구사항을 입증하지만, 요구사항이 존재하는 이유를 설명하지는 않습니다.
JLS는 그 이유를 § 15.27.2에서 언급하고 있다.
효과적인 최종 변수에 대한 제한으로 인해 동적으로 변화하는 로컬 변수에 대한 액세스가 금지되며, 이러한 변수가 캡처되면 동시성 문제가 발생할 수 있습니다.
버그 위험을 줄이기 위해 캡처된 변수가 변환되지 않도록 하기로 결정했습니다.
A final할 수 있음을 합니다.variable은 한 만 인스턴스화할 수 있습니다. 및할 수 Java에서는 lamda뿐만 아니라 익명 내부 클래스에서도 최종이 아닌 로컬 변수를 재할당할 수 없습니다.
각 루프에 대해 이전 코드를 리팩터링할 수 있습니다.
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;
}
이 코드의 일부를 이해하지 못하더라도:
- 'A'라고
v.getTimeZoneId();을 - 를
calTz = TimeZone.getTimeZone(v.getTimeZoneId().getValue());지나갔던 것은하지 않습니다.calTz이 하지 않습니다. - 반환을 합니다.
null, , , , , 을해 주세요.void★★★★★★★★★★★★★★★★★?
희망은 또한 이러한 팁들이 여러분이 발전하는 데 도움이 되기를 바랍니다.
람다에서는 최종적이지 않은 것에 대한 참조를 얻을 수 없습니다.변수를 고정하려면 lamda 외부에서 최종 래퍼를 선언해야 합니다.
마지막 '참조' 개체를 이 래퍼로 추가했습니다.
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에는 "Effective final" 변수라는 새로운 개념이 있습니다.즉, 초기화 후에도 값이 변경되지 않는 비최종 로컬 변수를 "효과적 최종"이라고 합니다.
이 개념은 Java 8 이전 버전에서는 익명 클래스에서 비최종 로컬 변수를 사용할 수 없었기 때문에 도입되었습니다.익명의 클래스에서 로컬 변수에 액세스하려면 최종적으로 접근해야 합니다.
람다가 도입되었을 때, 이 제한은 완화되었다.따라서 람다로 초기화된 후 변경되지 않으면 로컬 변수를 최종으로 만들어야 하는 것은 익명 클래스에 불과합니다.
자바8은 개발자가 람다를 사용할 때마다 로컬 변수 final을 선언하는 고통을 깨닫고 이 개념을 도입하여 로컬 변수를 final로 만들 필요가 없게 만들었다.따라서 익명 수업 규칙이 변경되지 않은 것을 알 수 있는 경우, 이 규칙을 작성하지 않아도 됩니다.final키워드를 지정합니다.
나는 여기서 좋은 설명을 찾았다.
이 예에서는, 를 치환할 수 있습니다.forEach간단한 람다와 함께for임의의 변수를 자유롭게 루프 및 수정할 수 있습니다.또는 변수를 수정할 필요가 없도록 코드를 리팩터링할 수도 있습니다.다만, 에러의 의미와 대처 방법에 대해서는, 완전하게 설명하겠습니다.
Java 8 언어 사양, § 15.27.2:
람다 식에서 사용되지만 선언되지 않은 로컬 변수, 형식 파라미터 또는 예외 파라미터는 final 또는 final로 선언되어야 합니다( either4.12.4). 그렇지 않으면 사용 시도 시 컴파일 시간 오류가 발생합니다.
기본적으로 로컬 변수는 변경할 수 없습니다(calTz이 경우 람다(또는 로컬/로컬 클래스) 내에서).Java에서 이를 실현하려면 가변 객체를 사용하여 람다에서 (최종 변수를 통해) 수정해야 합니다.여기서 나타내는 가변 객체의 예로는 1개의 요소의 배열을 들 수 있습니다.
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];
}
람다 식에 사용되는 변수는 최종 변수이거나 사실상 최종 변수여야 하지만 최종 요소 배열 하나에 값을 할당할 수 있습니다.
private TimeZone extractCalendarTimeZoneComponent(Calendar cal, TimeZone calTz) {
try {
TimeZone calTzLocal[] = new TimeZone[1];
calTzLocal[0] = calTz;
cal.getComponents().get("VTIMEZONE").forEach(component -> {
TimeZone v = component;
v.getTimeZoneId();
if (calTzLocal[0] == null) {
calTzLocal[0] = TimeZone.getTimeZone(v.getTimeZoneId().getValue());
}
});
} catch (Exception e) {
log.warn("Unable to determine ical timezone", e);
}
return null;
}
이러한 문제에 대한 일반적인 회피책보다 변수를 수정할 필요가 없는 경우 lambda를 사용하고 method-parameter에서 final 키워드를 사용하는 코드 부분을 추출합니다.
[ To answer to ]> 람다 표현에서 사용되는 변수는 최종 또는 사실상 최종 JAVA여야 합니다.
우아하지 않은 방법으로 그것을 회피하려면 , 2개의 문제: 부작용과 스레드화 문제
final AtomicInteger e = new AtomicInteger(0);
new Thread(() -> {
e.addAndGet(1);
});
좀 더 정확히 말하면, 람다 함수를 사용하는 이면에 있는 아이디어는 측면 효과를 피하기 위한 것이며, 외부에서 결과를 얻기 위해 값을 채우기 위해 람다 함수의 이 최종 참조에 액세스할 때, 우리는 이 개념을 깨고 있습니다.
가장 오래된 글에서 당신은 그렇게 다시 쓰고 싶을지도 모른다.
cal.get Components().get Components("VTIMEZONE").streams().map(v->v.getTimeZoneId().collect(Collectors.toList());
스레드화 측면에서는 부작용과 같은 문제가 발생하며 결과를 수집하기 위해 언제 Atomic 변수에 액세스해야 하는지 알 수 없습니다.Count Down Latch를 넣을 수 있습니다.Completeable과의 연계성 향상결과와 동기화 측면을 처리할 미래
언급URL : https://stackoverflow.com/questions/34865383/variable-used-in-lambda-expression-should-be-final-or-effectively-final
'programing' 카테고리의 다른 글
| 어떻게 C에 구조를 배열할 수 있을까요? (0) | 2022.09.03 |
|---|---|
| 메서드 이름을 문자열로 지정했을 때 Java 메서드를 호출하려면 어떻게 해야 합니까? (0) | 2022.09.03 |
| vue에서 이미지 크기를 조정하는 방법 (0) | 2022.09.03 |
| Vue에서 렌더링된 목록 내에서 모달 열기 (0) | 2022.09.03 |
| 명령줄을 통해 GNU make 변수에 추가 (0) | 2022.09.03 |