람다표현식을 활용하면 동작을 파라미터화 할 수 있음.
코드 가독성 개선이란 '어떤 코드를 다른 사람도 쉽게 이해할 수 있음'을 의미한다. 유지보수성 up!
3가지 예제를 다뤄볼 것이다.
Runnable r1 = new Runnable(){
public void run(){
System.out.println("Hello");
}
}
Runnable r2 = () -> System.out.println("Hello");
하지만 모든 익명 클래스를 람다 표현식으로 변환할 수 있는 것은 아니다.
첫째, 익명 클래스에서 사용한 this 와 super는 람다표현식에서 다른 의미를 가진다. 익명 클래스에서 this는 자기 자신을 가르키지만, 람다에서 this는 람다를 감싸는 클래스를 가리킨다.
둘째, 익명 클래스는 감싸고 있는 클래스의 변수를 가릴 수 있다.(섀도 변수) 하지만 다음 코드에서 보여주는 것처럼 람다 표현식으로는 변수를 가릴 수 없다.
int a = 10;
Runnable r1 = () ->{
int a =2; // 컴파일 에러
System.out.println(a);
}
Runnable r2 = new Runnable(){
public void run(){
int a = 2; // 잘 작동한다.
System.out.println(a);
}
};
마지막으로 익명 클래스를 람다 표현식으로 바꾸면 콘텍스트 오버로딩에 따른 모호함이 초래될 수 있다. 익명 클래스는 인스턴스화할 때 명시적으로 형식이 정해지는 반면 람다의 형식은 콘텍스트에 따라 달라지기 때문이다.
아래 코드에서는 Task라는 Runnable과 같은 시그니처를 갖는 함수형 인터페이스를 선언한다.
interface Task{
public void execute();
}
public stativ void doSomething(Runnable r){r.run();}
public stativ void doSomething(Task a){r.execute();}
Task를 구현하는 익명 클래스를 전달할 수 있다
doSomething(new Task(){
public void execute(){
System.out.println("Danger danger!!");
}
}
하지만 익명 클래스를 람다 표현식으로 바꾸면 메서드를 호출할 때 Runnable과 Task 모두 대상 형식이 될 수 있으므로 문제가 생긴다.
doSomething(()-> System.out.println("Danger danger!!"));
즉 doSomething(Runnable)과 doSomething(Task)중 어떤 것을 가르키는지 알지 못하는 모호함이 생긴다.
명시적 형변환 (Task)를 통해서 모호함을 제거할 수 있다.
doSomething((Task)()-> System.out.println("Danger danger!!"));
다행인 것은, IDE에서 이런 오류를 잡아준다!