람다 표현식
람다 표현식은 메소드로 전달할 수 있는 익명 함수를 단순화한 것이다.
특징
- 익명
- 보통의 메소드와 달리 이름이 없다.
- 함수
- 메소드처럼 특정 클래스에 종속되지 않아 함수라고 부른다.
- 전달
- 람다 표현식은 메소드 인수로 전달하거나 변수로 저장할 수 있다.
- 간결성
- 코드가 간결해진다.
람다 표현식은 파라미터, 화살표, 바디로 이루어진다.
- 파라미터
(Apple a1, Apple a2)
- 화살표
->
- 바디
a1.getWeight().compareTo(a2.getWeight());
그렇다면 람다 표현식은 어디에 사용할 수 있는걸까?
바로 함수형 인터페이스의 구현에 사용 가능하다
함수형 인터페이스란?
함수형 인터페이스의 예시에는 Predicate, Comparator, Runnable 등이 있다
public interface Predicate<T> {
boolean test (T t);
}
public interface Comparator<T> {
int compare(T o1, T o2);
}
public interface Runnable<T> {
void run();
}
이와 같이 하나의 추상 메소드만 가지고 있는 인터페이스를 함수형 인터페이스라고 한다.
함수형 인터페이스는 오직 하나의 추상 메소드만 가지고 있기 때문에 메소드의 동작을 파라미터화 할 수 있다.
@FunctionalInterface
interface CalculatorOperation {
int operate(int a, int b);
}
public class FunctionalInterfaceExample {
public static int calculate(int a, int b, CalculatorOperation operation) {
return operation.operate(a, b);
}
public static void main(String[] args) {
int sum = calculate(5, 3, new CalculatorOperation() {
public int operate(int x, int y) {
return x + y;
}
});
System.out.println("5 + 3 = " + sum); // 출력: 5 + 3 = 8
}
}
이제 추상 메소드를 구현한 부분을 람다함수로 바꾸는 과정을 보겠다.
아래는 함수형 인터페이스를 익명 클래스로 구현한 모습이다.
int sum = calculate(5, 3, new CalculatorOperation() {
public int operate(int x, int y) {
return x + y;
}
});
함수형 인터페이스는 하나의 추상 메소드만 가지고 있기 때문에 메소드가 추론된다.
메소드의 이름이나 타입도 명시할 필요가 없다.
그래서 자바 8에서 나온 것이 람다이다.
람다 표현식을 사용한다면 이렇게 코드를 줄일 수 있다.
int sum = calculate(5, 3, (int x, int y) -> {
return x + y;
});
람다 표현식의 간단화 작업은 이게 끝이 아니다.
한 줄의 반환문일 경우, 중괄호({})와 return 키워드를 생략할 수 있다.
int sum = calculate(5, 3, (int x, int y) -> x + y);
매개변수의 타입 역시 추론할 수 있기 때문에 매개변수의 타입 또한 생략할 수 있다.
int sum = calculate(5, 3, (x, y) -> x + y);
추상 메소드를 직접 구현해야 했던 초반에 비해 코드가 상당히 짧아진 것을 확인할 수 있다.
이러한 장점이 있지만 단점도 있다.
단점
1. 디버깅이 어렵다
람다 표현식은 익명 함수이므로 디버깅 시 stack trace에 정확한 위치나 이름이 나타나지 않아 추적에 어려움이 있다.
2. 재사용성이 부족하다.
람다 표현식은 이름이 없기 때문에 한번 정의된 람다 표현식을 여러 곳에서 재사용하기가 어렵다. 코드 중복이 생길 수 있다.
3. 복잡한 로직에 부적합하다.
복잡한 로직이 포함된 경우, 람다 표현식이 더 이해하기 어려울 수 있다.
4. 익명 클래스와 차이점
람다는 익명 클래스와 달리 this가 외부 클래스에 바인딩된다. 반면 익명 클래스는 해당 익명 클래스를 참조한다. 따라서 람다에서 익명 클래스의 this를 참조하려는 경우 문제가 발생할 수 있다.
결론
이와 같은 단점으로 람다 표현식은 하나의 람다 표현식 당 하나의 계산만을 담당해야 한다고 생각한다.
그리고 알아보기 어려운 로직의 경우 네이밍을 통해 리뷰어에게 의도를 전달해야 하는데 이 경우 익명 함수인 람다를 자제해야 한다. 또한 많이 쓰이는 로직의 경우에도 별도로 메소드를 선언하여 재사용성을 높이는 것이 좋을 듯하다.
그러나 구현체를 길게 써야하는 익명 클래스에 비해 이점이 있는 것은 분명하다. 함께 개발하는 동료들과 또는 자신만의 기준을 세워 적절히 활용하는 것이 좋다고 생각한다.