programing

람다 식에 사용되는 변수는 최종 변수이거나 사실상 최종 변수여야 합니다.

prostudy 2022. 9. 3. 09:16
반응형

람다 식에 사용되는 변수는 최종 변수이거나 사실상 최종 변수여야 합니다.

람다 식에 사용되는 변수는 최종 변수이거나 사실상 최종 변수여야 합니다.

★★★★★★★★★★★★★★★★★★★를 사용하려고 하면,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

반응형