메서드를 하나의 식으로 표현
함수형 프로그래밍 지원
자바에서는 람다식을 익명 구현 객체로 변환
람다 표현식의 기본 구조
(parameter1, parameter2) -> {
statement1;
statement2;
statement3;
...
}
람다식을 활용하면 변수에 함수를 할당할 수 있다.
MyFunction f = (x, y) -> x + y; f.sum();
new MyInterface(){
@Override
public void foo(int num){
System.out.println(num);
}
}
MyInterface mi = number -> System.out.println(number);
mi.foo(1) // 1 출력
위 코드와 같이 람다는 인터페이스를 선언하고 그에 대한 메서드를 정의한다는 점에서 익명객체와 비슷한 구조로 이루어져있다.
익명 객체를 람다식으로 표현하기 위해서는 인터페이스가 단 하나의 추상 메서드만 가져야한다.
그도 그럴 것이 람다는 메서드명, 타입을 모두 생략하고 표현하기 때문에 람다가 구현할 추상메서드는 하나이어야 한다.
이러한 추상메서드를 단 하나마 가지는 인터페이스를 함수형 인터페이스라고 한다.
람다 표현식의 요건
- 함수형 인터페이스가 필요.
- 매개변수와 반환 값의 타입 일치 필요.
- 로컬 변수는 final이어야 함.
단 하나의 추상 메서드를 지닌 인터페이스
@FunctionalInterfae
public interface MyFunction{
int sum(int a, int b);
}
@FunctionalInterface 에너테이션은 함수형 인터페이스를 구현할 때 2개 이상의 추상메서드가 선언되지 않도록 컴파일 타임에 체크하기 위함이다.
에너테이션은 선택 사항이나 붙이는걸 권장한다.
함수형 인터페이스는 아래와 같이 표준 API가 정의되어 있다.
| 인터페이스 | 메서드 | 설명 | 매개변수 | 리턴 |
|---|---|---|---|---|
Runnable |
void run() |
매개변수를 사용하지 않고, 리턴을 하지 않는 함수 형태로 이용 | ❌ | ❌ |
Consumer<T> |
void accept(T t) |
매개변수만 사용하고 리턴을 하지 않는 함수 형태로 이용 | ⭕ | ❌ |
Supplier<T> |
T get() |
매개변수를 사용하지 않고, 리턴을 하지 않는 함수 형태로 이용 | ❌ | ⭕ |
Function<T, R> |
R apply(T t) |
매개변수 값을 매핑(타입 변환)해서 리턴 | ⭕ | ⭕ |
Predicate<T> |
boolean test(T t) |
매개변수값이 조건에 맞는지 단정해서 boolean 리턴 | ⭕ | ⭕ |
Operator |
R applyAs(T t) |
매개변수값을 연산해서 결과 리턴 | ⭕ | ⭕ |
메서드를 참조해서 매개변수와 리턴타입의 정보를 알아내어 람다식의 불필요한 부분을 생략가능하다.
| 종류 | 람다 표현식 | 메서드 참조 |
|---|---|---|
정적 메서드 참조 |
(x) -> Class.method(x) |
Class::method |
인스턴스 메서드 참조 |
(x) -> obj.method(x) |
obj::method |
매개변수의 메서드 참조 |
(obj, x) -> obj.method(x) |
Class::method |
생성자 메서드 참조 |
(x, y) -> new Class(x, y) |
Class::new |
import java.lang.FunctionalInterface;
// 함수형 인터페이스 정의
@FunctionalInterface
interface MyFunction1 {
int sum(int a, int b);
}
public class Main {
public static void main(String[] args) {
// 익명 객체(익명 클래스)를 사용해 함수형 인터페이스 구현
MyFunction1 f0 = new MyFunction1() {
@Override
public int sum(int a, int b) { return a + b; }
};
// 람다 표현식으로 f1 변수에 함수를 저장
MyFunction1 f1 = (a, b) -> a + b;
// Integer 클래스 내의 sum 메서드를 참조함
MyFunction1 f2 = Integer::sum;
int res0 = f0.sum(1, 2);
int res1 = f1.sum(3, 4);
int res2 = f2.sum(5, 6);
// 메서드의 매개변수의 입력값으로 람다식을 넘김
int res3 = add((a, b) -> a + b);
System.out.println("익명객체 : " + res0); // 3
System.out.println("람다 : " + res1); // 7
System.out.println("메서드 참조 : " + res2); // 11
System.out.println("add메서드 : " + res3); // 3
}
public static int add(MyFunction1 lambda){
return lambda.sum(1, 2);
}
}