기본 콘텐츠로 건너뛰기

Java 람다함수에서 외부지역변수를 수정할 수 없는 이유

 C++ 하다 보면, 람다함수에서 외부지역변수 수정을 숨쉬듯이 하는 편인데, Java 에서 동일한 형태로 람다함수를 사용하려고 하면, 오류난다.

// Java
import java.util.function.Consumer;

public class MyClass {
    public String getString() {
        String result = "";

        Consumer<String> lamda = (String name) -> {
            result = "<<" + name + ">>";
        };

        return result;
    }

    public static void main(String[] args) {
        System.out.println("new MyClass().getString(): " + new MyClass().getString());
    }
}
// 컴파일 결과
// javac MyClass.java
// MyClass.java:8: error: local variables referenced from a lambda expression must be final or effectively final
//             result = "<<" + name + ">>";
//             ^
// 1 error
// C++
#include <iostream>
#include <string>
using namespace std;

class MyClass {
    public:
        string getString() {
            string result;

            auto lamda = [&] (string name) {
                result = "<<" + name + ">>";
            };

            lamda("Purewell");

            return result;
        }
};

int
main(int argc, char* argv[]) {
    cout << "(new MyClass())->getString()): " << (new MyClass())->getString() << endl;
}

// 실행결과: (new MyClass())->getString()): <<Purewell>>

위와 같이 C++에선 지역변수에 접근해서 값을 수정하였으나, Java에선 컴파일 타임에 문법 오류 난다.

사유는 Java에서 적극 사용하는 Thread인 듯 싶다.

지역변수는 Java에서 Thread끼리 공유하지 않는 Stack영역에 있고, 클래스 멤버변수들은 공유 가능한 Heap 영역에 있어서...라는데, 난 잘 모르겠다.

지역변수는 해당 메서드가 끝나면, 스택에서 사라진다. 만약 람다함수가 스레드를 사용하는 객체라면, 호출한 메서드(MyClass.getString())가 끝나도, 람다함수가 실행 중일 수 있다. 이때 캡쳐한 지역변수를 변경하려고 접근하려면, 이미 스택에서 사라진 변수에 접근하면서 오류가 발생할 것이다.

C++ 식이라면, 알아서 척척척 스스로 개발자가 모두 처리를 해야하지만, Java는 그런 경우를 아예 용납하지 않는 것 같다.

참조: https://www.baeldung.com/java-lambda-effectively-final-local-variables


댓글

이 블로그의 인기 게시물

설치한 패키지에서 RPM 추출하기

오래된 패키지를 관리할 저장소가 없어졌고, 기존 패키지로 다른 서버를 세팅해야할 일이 생겼다면 RPM의 리패키지 기능을 이용해보자. $ rpm -e --repackage [PACKAGE_NAME] 위와 같이 리패키지하면, /var/spool/repackage/ 에 생성한 RPM파일이 있다. :-)

Winget 해시 무시하기

가끔씩 Winget 에서 패키지를 다운로드 했을 때, "설치 관리자 해시가 일치하지 않습니다." 오류가 뜰 때가 있다. 보안 이슈가 있지만, 그냥 무시하고 싶을 때, 아래 순서로 무시해준다. 관리자 권한 winget settings --enable InstallerHashOverride 설치 winget install --ignore-security-hash --id NirSoft.NirCmd