- target: Java의 람다 표현식에서의 표현식 외부의 변수 사용
- method:
1. Lambda Expression
Method를 하나의 식으로 표현한 것
Method를 람다식으로 표현할 경우, 이름/반환값이 없어지므로, 이를 익명함수(Anonymous function)이라고도 함
Method를 변수처럼 다루는 것이 가능
2. 지역 변수 제약
Java8에서의 람다 표현식을 사용할 때, 람다 표현식 내부에서 자유변수(람다 표현식 기준 외부의 변수)의 값을 설정할 수 없음
람다 표현식 내부에서 사용이 불가능한 것이 아니라, 외부 변수를 재정의할 수 없음을 의미
이는 js에서 const 타입과 유사성을 보이지만, const 타입은 java의 final와 동일하고, 이 effectively final 변수는 람다 표현식 내부에서 람다 캡쳐링(=Lambda Capturing)을 통해서 설정 가능
※ js에서의 const / let 타입은 ES6 문법에서 추가되었으며, 광범위한 var 타입 변수의 보완으로 접근 제어 역할이 추가됨
3. Effectively final
Effectively final란 final 선언이 되어있지 않으나, 재할당이 발생하지 않는 변수를 의미
// 가능
String str = "Hello World";
Runnable r1 = () -> System.out.println(str);
// 불가능(최초 선언 및 초기화 이후에 str 변수가 변경되면서 람다 식 내부에서는 사용이 불가능
//str += "!";
//Runnable r2 = () -> System.out.println(str);
// 불가능(최초 선언 및 초기화 이후 람다 식 내부에 적용 이후에 변경하여도 사용이 불가능
//Runnable r3 = () -> System.out.println(str);
//str += "!";
※ 최초 변수 선언 및 초기화 이후에 해당 변수를 변경하는 경우 람다 식 내에서 사용할 수 없음
4. 동작 방식
인스턴스 변수는 heap에 저장, 지역변수는 stack에 저장
stack 영역은 heap과 달리 각 thread간에 공유되지 않는 영역
자유 변수는 람다 캡쳐링에 의해 복사되기 때문에 다른 thread에서 참조할 수 있으나, 람다 표현식 실행 시점차로 인해, Sync를 맞출 수 없기에 effectively final로 쓰임
※ 클래스 변수는 thread간에 공유되는 method 영역에 저장
5. Lambda Capturing
람다 식은 다른 thread에서도 실행 가능
만약 A thread에서 생성한 람다 식을 B thread에서 사용할 경우, 인스턴스 변수는 thread간에 공유가 가능한 heap 영역에 저장되어 공유가 가능하지만, stack영역에 있는 지역변수는 외부 thread에서 접근이 불가능
따라서, stack영역에 있는 변수를 사용할 수 있도록 지역 변수의 복사본을 제공해서 람다 식에서 접근 가능하도록 설정
(= Lambda Capturing)
하지만, 원래 stack에 저장된 지역 변수의 값이 바뀌면 capturing한 람다 식 내부의 변수와의 동기화가 보장되지 않기 때문에 동시성 이슈가 발생
따라서 지역 변수는 final임이 보장되어야 함
5. 적용 방법
간혹가다가 람다 표현식 내부에서 외부 변수를 참조해야하는 경우가 생기는데(합계출력이나, 일괄 문자열 append 시)
아래와 같은 방식으로 해결가능
람다 표현식의 경우, Effectively final 변수를 컨트롤 할 수 없기 때문에 아래와 같은 코드는 불가능
String word = "Hello";
// array = ['W','o','r','l','d']
array.stream().forEach(item -> word += item;);
Effectively final 변수를 forEach안의 람다 표현식 내부에서 설정을 시도하기 때문에 불가능
대신 아래와 같은 코드는 가능
StringBuffer word = new StringBuffer();
word.append("Hello");
// array = ['W','o','r','l','d']
array.stream().forEach(item -> word.append(item););
- source:
https://bcp0109.tistory.com/319
effectively final: 람다 표현식 내에서 사용하는 변수가 final 처럼 사용되어야 하는 이유
1. Overview Java 의 람다 표현식은 익명 함수처럼 자유 변수 (Free Variable) 를 활용할 수 있습니다. 여기서 자유변수란 파라미터로 넘겨진 변수가 아닌 외부에서 정의된 변수 를 의미합니다. 2. 지역 변
bcp0109.tistory.com
https://ryan-han.com/post/dev/java-lambda/
자바의 정석 - 람다식(Lambda Expression) | Integerous DevLog
자바의 정석 - 람다식(Lambda Expression) 2018/11/29 자바의 정석(남궁성 저) 2권 학습내용 정리 1. 람다식 메서드를 하나의 식(expression)으로 표현한 것. 메서드를 람다식으로 표현하면 메서드의 이름과
ryan-han.com
'Dev > Java' 카테고리의 다른 글
[Java 8+] Stream to map 및 Method Reference (0) | 2022.08.08 |
---|---|
Stream을 통한 Map에서의 원하는 키 추출 및 별도 Map 생성 (0) | 2022.08.05 |
[logback] logback.xml (0) | 2022.06.21 |
[Jvm] JAVA_OPTS 설정 (0) | 2022.06.20 |
HashMap pulAll & merge (0) | 2022.06.15 |