정리 :
람다식은 final or effective final 일 경우 로컬변수 참조가 가능하다.
로컬 클래스, 익명클래스, 람다 표현식 중, 람다만 유일하게 스코프가 같아서 쉐도잉 이슈가 없다.
람다
● (인자 리스트) -> {바디}
인자 리스트
● 인자가 없을 때: ()
● 인자가 한개일 때: (one) 또는 one
/**
* 인자가 2개인 경우에
*/
BinaryOperator<Integer> sum = (a,b) -> a + b;
● 인자가 여러개 일 때: (one, two)
● 인자의 타입은 생략 가능, 컴파일러가 추론(infer)하지만 명시할 수도 있다. (Integer one, Integer two)
바디
● 화상표 오른쪽에 함수 본문을 정의한다.
● 여러 줄인 경우에 { }를 사용해서 묶는다.
/**
* 인자가 없는 supplier같은 경우 () 인자리스트를 비우면 된다.
*/
Supplier<Integer> get10 = () -> 10;
● 한 줄인 경우에 생략 가능, return도 생략 가능.
변수 캡처 (Variable Capture)
● 로컬 변수 캡처
○ final이거나 effective final 인 경우에만 참조할 수 있다.
○ 그렇지 않을 경우 concurrency 문제가 생길 수 있어서 컴파일러가 방지한다.
로컬 클래스, 익명 클래스, 람다 표현식의 공통점
● effective final( 사실상 final인 경우. final은 아니지만 해당 변수를 어디서도 변경하지 않는 경우를 말한다.)
○ 이것도 역시 자바 8부터 지원하는 기능으로 “사실상" final인 변수.
○ final 키워드 사용하지 않은 변수를 참조할 수 있다.
차이
● 익명 클래스 구현체와 달리 ‘쉐도윙’하지 않는다.
쉐도잉 : 같은 이름의 여러 로컬 변수중, 가장 안쪽의 로컬 변수가 우선 참조된다. 외부의 로컬 변수값은 무시된다.
int baseNumber = 10;
/* Class LocalClass {
void printBaseNumber() {
System.out.println(baseNumber);
}
}*/
/**
* 익명 클래스 내부에서 로컬변수 참조하는 방법
*/
Consumer<Integer> integerConsumer = new Consumer<Integer>() {
int baseNumber = 11;
@Override
public void accept(Integer baseNumber) {
System.out.println(baseNumber);
}
};
익명클래스 내부에서 baseNumber를 재정의하면 print시 10이 아닌 11로 출력된다. 내부 스코프가 우선.
또한 파라미터 명을 baseNumber로 변경하게 되도 외부가 아니라 파라미터 값이 우선이 된다.
쉐도잉 이슈 존재.
람다의 경우 같은 스코프이므로, 컴파일 에러가 바로 발생한다.
○ 익명 클래스, 내부클래스는 새로 스콥을 만들지만, 람다는 람다를 감싸고 있는 스콥과 같다.
또한 effective final이 아니게 되도 바로 컴파일에러로 확인할 수 있다.
참고
● https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html#shadowing
● https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html
'스프링 스터디 (인프런) > 더 자바 8' 카테고리의 다른 글
인터페이스의 변화 - 인터페이스 기본 메소드와 스태틱 메소드 (0) | 2023.04.08 |
---|---|
함수형 인터페이스와 람다 - 메소드 레퍼런스 (0) | 2023.04.06 |
함수형 인터페이스와 람다 - 자바에서 제공하는 함수형 인터페이스 (0) | 2023.04.01 |
함수형 인터페이스와 람다 (0) | 2022.12.07 |
소개 - 자바 8 소개 (0) | 2022.11.15 |