람다에 대하여 다루어 보고자 한다. C++에서의 람다와 캡처에 대한 개념을 정리 후, Java에서는 어떤지 정리할 것이다.
[캡처] (매개 변수) {함수 로직} (호출 인자)
매개변수의 경우 매개 변수가 필요없을 때, 생략할 수 있다. 호출 인자 또한 함수 호출이 아닌 경우에는 생략 가능하다.
람다 함수에서 가장 큰 특징은 캡처 부분이다. 람다 함수 안에서 참조할 바깥 변수를 지정하여 람다 함수에서 사용할 수 있다.
물론 매개 변수로 넘겨서 사용해도 캡처 없이 어느 정도 상황들은 대처할 수 있다. 하지만 인자를 많이 넘겨야 하는 경우 번거로울 수 있어 캡처를 사용하면 편리하게 람다가 접근할 변수들을 지정해 줄 수 있다.
람다 캡처에도 두 가지 방식이 있다.
- 값을 복사는 것
- 참조를 넘기는 것
캡처라는 단어에서 알 수 있듯, 그 순간의 람다 외부의 값을 이용하는 것으로 값을 복사해서 넘길 경우 기본적으로 const
속성을 가진다. 대신 참조로 넘길 경우 수정이 가능해진다. 참조로 넘길 경우는 당연히 기존 주소에 접근하기 때문에 참조 변수의 값을 변경할 수 있다.
[result1, result2] () {} () // 변수 result1, result2를 복사해서 람다 함수 내부에서 사용
[&result1, &result2] () {} () // 변수 result1, result2 를 참조해서 람다 함수 내부에서 사용
[result3, &result4] () {} () // 변수 result3은 복사 result4는 참조해서 람다 함수 내부에서 사용
[=] () {} () // 모든 외부 변수를 복사해서 람다 함수 내부에서 사용
[&] () {} () // 모든 외부 변수를 참조해서 람다 함수 내부에서 사용
[&, result3] () {} () // 모든 외부 변수는 참조로 사용하지만, result3만 복사로 사용
[=, &result3] () {} () // 모든 외부 변수는 복사로 사용하지만, result3만 참조로 사용
[this] () {} () // 클래스 멤버 함수의 경우 자기 자신을 전달 가능, [=]으로도 전달 됨
(매개 변수) -> {함수 로직}
Java에서는 매개 변수로 넘겨진 변수가 아닌 외부에 정의된 변수를 자유 변수라고 부른다. 그리고 자유 변수를 참조하는 행위를 람다 캡처링이라고 한다. C++과는 다르게 캡처링에 제약 조건이 있다.
- 외부 지역 변수는
final
로 선언되어 있거나,final
이 아니면final
처럼 동작해야한다.
람다가 실행될 때, 그 순간 로컬 스택을 캡처링을 한다. 여기서 외부 지역 변수 값을 재할당하려 시도하면 final
이어야 하기에 에러가 난다. C++에서 값 복사 시, const
로 넘어가는 부분과 일맥상통하는 것으로 보인다.
물론 이것은 값에 대한 이야기이고 heap의 주소값을 넘기는 경우는 주소에 접근해서 수정이 가능하다. 즉, 참조값을 넘기는 경우는 해당 객체 참조값 자체에 다른 주소값을 할당 하지만 않으면 객체 주소에 접근해서 수정하는 것은 문제가 없다. 참조값이 final로 다루어진다는 것이다.
예를 들어 List
를 캡처했다면 리스트에 add
하는 것은 상관 없지만 새로운 List
를 new
해서 할당하는 것은 안된다.
C++ - 람다와 클로저의 차이는 클래스와 클래스 인스턴스 사이의 차이점과 동일하다.
Java - 람다식 내에 자유변수가 사용되는 것을 클로저(Closure)라고 한다.
https://blockdmask.tistory.com/491
https://jungwoong.tistory.com/51
https://velog.io/@jylee9937/Java-Lambda%EC%99%80-Closure%EC%9D%98-%EA%B4%80%EA%B3%84
https://futurecreator.github.io/2018/08/09/java-lambda-and-closure/
https://perfectacle.github.io/2019/06/30/java-8-lambda-capturing/
https://velog.io/@kmdngmn/Java-%EB%9E%8C%EB%8B%A4-%EC%BA%A1%EC%B2%98%EB%A7%81-Lambda-Capturing-Java-8