[Java] 람다 표현식 소개
람다 표현식?
람다 표현식은 메서드로 전달할 수 있는 익명 함수를 단순화한 것이다.
람다 표현식에는 이름은 없지만, 파라미터 리스트, 바디, 반환 형식, 발생할 수 있는 예외 리스트는 가질 수 있다.
특징
- 익명: 보통의 메서드와 달리 이름이 없으므로 익명이라 표현한다.
- 함수: 람다는 메서드처럼 특정 클래스에 종속되지 않으므로 함수라고 부른다.
- 전달: 람다 표현식을메서드 인수로 전달하거나 변수로 저장할 수 있다.
- 간결성: 익명 클래스처럼 많은 자질구레한 코드를 구현할 필요가 없다.
람다 표현식을 이용하면 동적 파라미터 형식의 코드를 더 쉽게 구현할 수 있다.
예를 들어, Comparator 객체를 기존보다 간단하게 구현할 수 있다.
[기존]
Comparator<Apple> byWeight = new Comparator<Apple>() {
public int compare(Apple a1, Apple a2) {
return a1.getWeight().compareTo(a2.getWeight());
}
};
[람다]
Comparator<Apple> byWeight = (Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight());
람다 표현식은 위 코드에서 볼 수 있듯 파라미터 리스트, 화살표, 바디 세 부분으로 이루어진다.
사용
람다 표현식을 어디에 사용할 수 있는지 한 번 알아보자.
함수형 인터페이스
이전에 Predicate<T> 인터페이스로 필터 메서드를 파라미터화 한 것을 봤을 것이다.
public interface Predicate<T> {
boolean test(T t);
}
Predicate<T>는 함수형 인터페이스로, 오직 하나의 추상 메서드만 지정한다. 즉, 함수형 인터페이스는 정확히 하나의 추상 메서드를 지정하는 인터페이스다.
이외에도 자바 API의 함수형 인터페이스에는 Comparator, Runnable 등이 있다.
public interface Comparator<T> {
int compare(T o1, T o2);
}
public interface Runnable {
void run();
}
여기서 주의할 것은, 인터페이스가 많은 디폴트 메서드를 포함하고 있더라도 추상 메서드가 오직 하나면 함수형 인터페이스라는 것이다.
람다 표현식으로 함수형 인터페이스의 추상 메서드 구현을 직접 전달할 수 있으므로, 전체 표현식을 함수형 인터페이스의 인스턴스로 취급할 수 있다.
다음은 Runnable을 통해 구현한 람다 표현식이다.
Runnable r1 = () -> System.out.println("1"); // 람다
Runnable r2 = new Runnable() { // 익명 클래스
public void run() {
System.out.println("2");
}
};
public static void process(Runnable r) {
r.run();
}
process(r1);
process(r2);
process(() -> System.out.println("3")); // 직접 전달한 람다 표현식
함수 디스크립터
함수형 인터페이스의 추상 메서드 시그니처는 람다 표현식의 시그니처를 가리킨다.
람다 표현식의 시그니처를 서술하는 메서드를 함수 디스크립터라고 부른다.
예를 들어, Runnable 인터페이스의 유일한 추상 메서드 run은 인수와 반환값이 없으므로 Runnable 인터페이스는 인수와 반환값이 없는 시그니처로 생각할 수 잇다.
람다 표현식은 변수에 할당하거나 함수형 인터페이스를인수로 받는 메서드로 전달할 수 있으며, 함수형 인터페이스의 추상 메서드와 같은 시그니처를 갖는다.
예를 들어, 위 예제에서 다음과같이 process 메서드에 직접 람다 표현식을 전달했다.
public void process(Runnable r) {
r.run();
}
process(() -> System.out.println("Lambda"));
위 코드를 실행하면 'Lambda' 가 출력된다. () -> System.out.println("Lambda")은 인수가 없으며 void를 반환하는 람다 표현식이다. 이는 Runnable 인터페이스의 run 메서드 시그니처와 같다.
다음 코드는 유효하지 않은 람다 표현식이다.
Predicate<Apple> p = (Apple a) -> a.getWeight();
위 코드의 시그니처는 (Apple) -> Integer 이므로 Predicate<Apple>: (Apple) -> boolean의 test 메서드의 시그니처와 일치하지 않기 때문이다.
@FunctionalInterface
자바 API를 살펴보면 함수형 인터페이스에 @FunctionalInterface 어노테이션이 추가되어 있는 것을 확인할 수 있다.
@FunctionalInterface는 함수형 인터페이스임을 가리키는 어노테이션으로, @FunctionalInterface로 인터페이스를 선언했지만 실제로 함수형 인터페이스가 아니면 컴파일러가 에러를 발생시킨다.
예를 들어, 추상 메서드가 한 개 이상이라면 "Multiple nonoverridng abstract methods found in interface Foo"같은 에러가 발생할 수 있다.
'Language > Java' 카테고리의 다른 글
[Java] 람다 타입 검사/추론/제약 (0) | 2023.04.04 |
---|---|
[Java] 함수형 인터페이스 (0) | 2023.04.03 |
[Java] 동작 파라미터화 코드 전달하기 (0) | 2023.03.28 |
[Java] 바이트코드 조작 (0) | 2023.03.22 |
[Java] JVM (0) | 2023.03.20 |
댓글
이 글 공유하기
다른 글
-
[Java] 람다 타입 검사/추론/제약
[Java] 람다 타입 검사/추론/제약
2023.04.04 -
[Java] 함수형 인터페이스
[Java] 함수형 인터페이스
2023.04.03 -
[Java] 동작 파라미터화 코드 전달하기
[Java] 동작 파라미터화 코드 전달하기
2023.03.28 -
[Java] 바이트코드 조작
[Java] 바이트코드 조작
2023.03.22