BackEnd/Java

[Java] 람다와 익명클래스의 scope

샤아이인 2022. 1. 23.

주말에 팀 slack에 재미있는 내용이 올라와 공부후 정리해 본다.

 

1. 문제 상황

내가 읽었던 유명한 자바 책 에서는 람다는 익명클래스 라고 나와있었다.

이는 틀린말이 아니다. 다만 정확하게 "익명클래스 == 람다" 가 아니라는 점에서 문제점이 발생한다.

다음 예시를 살펴보자.

anonymous 는 익멱 클래스를 활용한 코드이며, lambda는 람다식을 활용한 코드이다.

두 코드 하는 역할은 동일한데, lambda 쪽에서 number 라는 변수를 사용할려 할면 문제가 발생한다.

(" 'number' 라는 변수는 초기화 되어있지 않기 때문" 이라는 경고를 보여준다)

 

다음 코드의 일부를 살펴보자.

private final int number

Predicate<Integer> lambda = (factor) -> number % factor == 0;

 

두 number는 동작시점에 동일한 number가 아닙니다.

 

람다는 외부의 값을 참조해서 읽고 복사한 후 이를 사용합니다. 

하지만 현재 Number클래스 내부에서는 number필드 변수에 final 키워드가 있으면서 값을 명시적으로 할당해주지 않았고,

값이 할당되어 있지 않은 number를 lambda 필드가 사용하려 들기 때문에 문제가 발생한것 입니다.

 

즉, 초기화 되지 않은 변수를 사용했기 때문에 발생한 문제입니다.

 

원래 자바의 final 키워드가 붙으면 선언 시점에 명시적으로 값을 할당해 줘야 정석입니다.

하지만 final 필드는 생성자를 통해 값을 할당받을 수 있다면 문제없이 사용이 가능합니다.

 

문제는 생성자를 통해 number를 초기화 하지 않은 상황에서 number를 사용하려 드니 문제인것 입니다. 

여기서 final을 빼면 오류가 사라지게 되는데, 이때는 자동으로 0이 할당되기 때문에 오류가 나지 않습니다.

 

2. 람다와 익명클래스의 scope

 

아니 그럼 익명 클래스 에서는 왜 사용이 가능할까?

 

두 number 간의 scope가 다르기 때문에 이런 현상이 발생한것 입니다.

익명 클래스와 람다 표현식은 실제론 다른 스코프 규칙을 갖는다고 합니다.
 
  • 익명 클래스는 객체가 생성되고 이후에 생성되는 규칙이라 초기화된 number를 스코프로 가질 수 있는 것이고
  • lambda는 완전히 lexical scope 규칙을 가져서 선언 시점에 초기화되지 않은 number에 접근하는 형태라 에러가 발생하는 것.

 

참고

 

 

Lambda Expressions (The Java™ Tutorials > Learning the Java Language > Classes and Objects)

The Java Tutorials have been written for JDK 8. Examples and practices described in this page don't take advantage of improvements introduced in later releases and might use technology no longer available. See Java Language Changes for a summary of updated

docs.oracle.com

 

 

Difference between final and effectively final

I'm playing with lambdas in Java 8 and I came across warning local variables referenced from a lambda expression must be final or effectively final. I know that when I use variables inside anonymous

stackoverflow.com

 

댓글