둘셋 개발!

[JAVA] 람다식에서 지역변수의 값을 변경하지 못하는 이유 본문

카테고리 없음

[JAVA] 람다식에서 지역변수의 값을 변경하지 못하는 이유

23 2024. 11. 11. 23:32

intro.
특정 카테고리의 갯수를 알기 위해, 지역변수로  cnt를 선언하고
List로 담겨진 아이템을 스트림을 사용하여, 특정 카테고리인 아이템의 갯수를 카운팅하려 했다.
하지만 오류를 만났다.
 

문제의 코드

int cnt = 0;
List<Integer> numbers = List.of(1,2,3,4,5,6);

// number에 담긴 짝수 갯수를 구한다.
numbers.forEach(
    n -> if (n %2 == 0) cnt++;
);

이렇게 코드를 작성하면, cnt++라는 부분에 빨간줄이 쳐지면서, 오류가 발생한다.
 

Variable used in lambda expression should be final or effectively final
람다식 표현에서 사용된 변수는 final이거나 effectively final이여야 한다.
 

 

왜 오류가 나는가?

람다식 표현에서 왜 지역변수의 값을 변경하지 못할까?
답은 메모리 구조에 있다.

멀티 쓰레드의 메모리 구조

(출처: https://thsd-stjd.tistory.com/149)
 

각 쓰레드는 독립적인 스택 메모리를 가지고 있다.
그리고 지역변수는 쓰레드의 스택 메모리에 저장된다.
그림에서 보다시피 스택메모리는 쓰레드끼리 공유를 하고 있지 않다.
 
람다식을 실행하는 것도 쓰레드이다.
그래서 람다식을 실행하는 쓰레드와 지역변수를 포함한 메서드를 실행하는 쓰레드는 다를 수 있기 때문에
서로 사용하는 스택 메모리가 다를 수 있다.
 
그래서 람다내에서 지역변수를 참조하여 값을 변경하지 못한다.
 
하지만 참조만 하는 것은 가능한다.
람다식에서 지역변수를 참조하는 경우, 해당 변수의 값을 복사하여 힙 메모리에 저장한다.
힙 메모리는 위의 메모리 구조에서도 보다시피 쓰레드끼리 공유하는 메모리이다.


ref.

 https://code-killer.tistory.com/202