람다 표현식에서는 익명 함수가 하는 것처럼 자유 변수(파라미터로 넘겨진 변수가 아닌 외부에서 정의된 변수)를 사용할 수 있다.
이와 같은 동작을 람다 캡처링이라고 부른다.
람다에서는 인스턴스 변수와 정적 변수는 제약없이 캡처하여 사용할 수 있다. 즉 자신의 바디 영역에서 언제든지 사용할 수 있다는 의미이다.
하지만 지역 변수는 제약 사항이 있다.
final로 선언되어 있거나 실질적으로 final로 선언된 변수와 똑같이 사용되어야 한다.
즉 한번 할당한 지역 변수를 두번 할당하지 않는 지역변수만 람다에서 사용가능하다는 뜻이다.
아래 내용은 가능함.
int message = "hi";
Runnable r = () -> System.out.println(message);
아래 내용은 가능하지 않음.
int message = "hi";
Runnable r = () -> System.out.println(message);
message = "bye";
그렇다면 지역변수에만 이러한 제약이 있는 이유는 무엇일까?
그 이유는 인스턴스 변수는 힙에 저장되지만 지역 변수는 스택에 위치하기 때문이다.
람다가 실행되는 스레드에서 지역 변수를 참조할 때는 지역 변수의 복사본(읽기 전용)을 생성하고 참조하게 된다. 람다가 직접 지역 변수가 위치한 스택에 접근하게 되면 지역 변수가 할당한 스레드가 사라져 변수 할 당이 해제되었는데도 람다를 실행하는 스레드가 해당 변수를 접근하고자 하는 경우가 발생하게 되기 때문이다.
이와 같이 복사본(읽기 전용)을 사용하기 때문에 해당 변수의 값은 변경되어서는 안된다는 제약이 발생하게 된 것이다.
람다는 클로저를 지원 하는가?
자바8의 람다와 익명 클래스는 클로저와 비슷한 동작을 수행한다.
람다와 익명 클래스 모두 메서드의 인수로 전달될 수 있으며 자신의 외부 영역의 변수에 접근할 수 있다. 하지만 람다와 익명 클래스는 람다가 정의된 메서드의 지역 변수의 값은 바꿀 수 없다.
*참고 : Java 8 in Action (한빛 미디어)
'JAVA' 카테고리의 다른 글
[Reactive Java] Spring WebFlux에서 Error 다루기 (0) | 2021.02.23 |
---|---|
[JAVA8] 람다 표현식을 조합할 수 있는 유용한 메서드 알아보기 (0) | 2019.04.19 |
[JAVA8] 함수형 인터페이스 정리 (0) | 2019.04.15 |
[JAVA] OkHttp로 REST API 호출하기 (0) | 2019.01.18 |
[JAVA] HttpClient로 REST API 호출하기 (0) | 2019.01.18 |