본문 바로가기

Development/Java

익명 클래스 → 람다 표현식 변환 시 주의할 점.

익명클래스에 비하여 람다표현식의 가독성은 굉장히 우수하다.

아래의 예를 보자.

(line 1:6)line 8 은 동일한 의미이다 !

1
2
3
4
5
6
7
8
Runnable runnable1 = new Runnable() {
    @Override
    public void run() {
        System.out.println("Hi");
    }
};
 
Runnable runnable2 = () -> System.out.println("Hi");
cs



하지만, 익명 클래스를 람다 표현식으로 변환 하고자 할때 몇 가지 주의할 점이 있다.


1. '익명 클래스'와 '람다 표현식'의 this는 다른 의미이다.



익명클래스의 this 는 익명클래스 자신을 지칭하지만, 람다 표현식에서의 this 는 선언된 클래스를 가리킨다.


예를 들면, 다음 코드에서


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class MyTestClass {
    public void foo() {
 
        Function<String, Integer> function1 = new Function<String, Integer>() {
            @Override
            public Integer apply(String s) {
                System.out.println(this.toString());
                return s.length();
            }
        };
 
 
        Function<String, Integer> function2 = s -> {
            System.out.println(this.toString());
            return s.length();
        };
 
    }
}
cs



익명클래스의 this (line 7)는 익명 클래스 자신을 가리키며,


람다표현식의 this (line 14)는 MyTestClass를 가리킨다.




2. '익명 클래스'와 달리 '람다 표현식'은 은닉 변수(Shadow Variable)을 허용하지 않는다.



1
2
3
4
5
6
7
8
public void foo() {
    Integer number = 100;
    
    Function<String, Integer> function = s -> {
        Integer number = 100; //compile Error
        return number;
    };
}
cs


위 코드는 컴파일에러가 발생한다.




3. '람다 표현식'은 같은 시그니처를 가지는 인터페이스에 대하여 의미가 모호해 진다.



무슨 말이냐면 ! 아래 코드를 보자.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
interface Task {
    void execute();
}
 
interface Work {
    void process();
}
 
public static void action(Task task) {
    task.execute();
}
 
public static void action(Work work) {
    work.process();
}
 
public void foo() {
    
    action(new Task() {
        @Override
        public void execute() {
            System.out.println("Hi");
        }
    });
    
    action(()-> System.out.println("Hi")); //Task? Work? Ambiguous !
 
    action((Task) () -> System.out.println("Hi"));
 
}
cs


(line 1:16) 까지는 기본 셋팅이다.

자. 이 상황에서 (line 19:24) 의 익명클래스를 람다 표현식으로 바꾸고자 할때, line 26 처럼 변경하게 되면, 이 람다표현식이 Task에 관한 것인지 Work에 관한 것인지 의미가 모호해 진다. 따라서 이럴 경우에는 앞에 캐스팅 마크를 붙여 (Task)라고 명시해주어야 한다.





참고 : Java 8 In Action