[자바] Lambda에서 사용 가능한 변수(Stack과 Heap)
자바 람다식에선 지역변수 접근이 불가능합니다.
스택오버플로우에서 이미 토론된 바 있습니다.
그 중 아래의 답변이 괜찮아 보이네요.
You may be asking yourself why local variables have these restrictions. First, there’s a key difference in how instance and local variables are implemented behind the scenes. Instance variables are stored on the heap, whereas local variables live on the stack. If a lambda could access the local variable directly and the lambda were used in a thread, then the thread using the lambda could try to access the variable after the thread that allocated the variable had deallocated it. Hence, Java implements access to a free local variable as access to a copy of it rather than access to the original variable. This makes no difference if the local variable is assigned to only once—hence the restriction. Second, this restriction also discourages typical imperative programming patterns (which, as we explain in later chapters, prevent easy parallelization) that mutate an outer variable.
지역변수는 스택에, 인스턴스 변수는 힙에 저장됩니다.
만약 람다에서 지역 변수에 바로 접근이 가능하다면, A 쓰레드에서 람다가 사용될 때 (그 지역변수를 할당했던) B 쓰레드가 지역변수 할당을 해제 후 그 지역변수에 접근할 수 있기 때문이라고 합니다.
흠.. 사실 이것만 가지고는 잘 이해가 되질 않네요. 쓰레드마다 각각의 고유한 스택 공간을 사용하지 않나요?
A 쓰레드가 B쓰레드의 지역변수에 접근이 가능한가요? 흠;;
(이건 좀 다른 이야기 같습니다. 쓰레드마다 고유한 스택 공간을 가지는 것을 이야기할 때는 동등한? 성격의 쓰레드에서 고유한 지역변수를 가진다는 것이고.. 람다와 같은 익명클래스에선 동등한? 쓰레드가 아닌 것 같습니다. 흠..
람다에서 보면 람다를 호출하는 쓰레드와 람다를 실행하는 쓰레드 이렇게 나뉘니까요. 람다를 실행하는 쓰레드에는 기본적으로 람다와 관련된 지역변수만 있을 것 같습니다.)
일단은 이렇게 이해를 해야겠습니다.
람다에서 사용하는 변수는 capture라 해서 읽기 전용으로 복사를 해서 사용하기 때문에 동시성 문제가 안생기도록 final을 요구한다 라구요.(docs.oracle.com/javase/specs/jls/se10/html/jls-15.html#jls-15.27.2)
The restriction to effectively final variables prohibits access to dynamically-changing local variables, whose capture would likely introduce concurrency problems.
동적으로 값이 변하는 지역변수의 경우, 이 람다의 캡쳐(이 지역변수를 읽기 전용으로 복사해서 사용하는)가 동시성 문제를 발생시킬 수 있기 때문입니다.
*추가 내용
stackoverflow.com/a/49053483/7225691글을 보겠습니다.
You can refer this article - https://www.infoq.com/articles/Java-8-Lambdas-A-Peek-Under-the-Hood explained on lambda expressions compilation. As explained lambda expressions/blocks of code are compiled into the anonymous class, these anonymous class are compiled with the name format (<<Enclosing Class name>>$<<1(Number)>>), so suppose assume if non final local variables are allowed then compiler cannot trace it from where this local variable is referred as anonymous class' '.class' files are created/compiled with aforementioned format separately like normal java classes.
So if local variable is final then compiler creates a final instance in the anoymous class which doesn't create ambiguity to compiler. Refer the link mention above for more information
람다식은 익명 클래스로 컴파일 되는데 이 익명 클래스는 <<Enclosing Class name>>$<<1(Number)>> 형식으로 만들어집니다. 그렇기에 만약 일반 지역 변수가 허락되고 컴파일 된다면, 컴파일러는 익명 클래스에서 이 지역변수를 찾을 수 없습니다.
stackoverflow.com/a/4732617/7225691
When you create an instance of an anonymous inner class, any variables which are used within that class have their values copied in via the autogenerated constructor.
(생략)
As the value has been copied into the instance of the anonymous inner class, it would look odd if the variable could be modified by the rest of the method
익명 클래스에서 사용하는 모든 변수는 자동으로 만들어진 생성자에 의해 복사가 된다고 합니다. 그런데 만약 다른 함수에 의해 이 지역변수 값이 변경된다면 이상할 것입니다.
제가 이해한 바는 아래와 같습니다.
lambda식은 익명 클래스처럼 동작하기 때문에 익명 클래스 같은 규칙을 적용받습니다.
익명 클래스에서는 final(effectively final)이 아닌 외부 지역 변수에 접근할 수 없습니다.
참고
stackoverflow.com/questions/25055392/lambdas-local-variables-need-final-instance-variables-dont
digitalbourgeois.tistory.com/68
stackoverflow.com/questions/12825847/why-are-local-variables-thread-safe-in-java
docs.oracle.com/javase/tutorial/java/javaOO/anonymousclasses.html
stackoverflow.com/a/13830900/7225691
tutorials.jenkov.com/java-concurrency/java-memory-model.html
댓글 영역