람다식을 메서드로 바꾸는 방법은 어렵지 않다.
- 메서드
int max(int a, int b) {
return a > b ? a : b;
}
int printVar(String name, int i) {
System.out.println(name + "=" + i);
}
int square(int x) {
return x * x;
}
int roll() {
return (int) (Math.random()*6);
}
- 람다식
(a, b) -> a > b ? a : b
(name, i) -> System.out.println(name + "=" + i)
x -> x * x
() -> (int) (Math.random()*6)
람다식은 익명 객체
람다식은 함수형 언어의 기능을 객체지향 언어인 자바에 일부 이식을 한 존재다. 람다식을 사용하면 장황하게 표현되는 메서드를 보다 쉽고 보기 좋게 사용할 수 있게 된다.
메서드를 람다식으로 만들 때에는 메서드의 반환 타입과 이름을 제거해주기 때문에 람다식으로 표현된 메서드는 이름이 없어 보여 익명 함수
라고 부르기도 한다. 하지만 조금 더 생각해보자. 자바는 모든 것이 클래스 기반으로 이루어져 있다. 위에서 작성한 int max
, int printVar
와 같은 메서드도 어떤 클래스에 포함되어 있을 것이며, 자바 프로그램의 시작지점인 main
역시 특정 클래스 내부에 존재하고 있다.
람다식 역시 이 규칙에서 예외가 아니다. 자바에는 익명 객체
가 존재한다. 익명 함수
와 마찬가지로 이름이 없는 객체를 표현할 수 있는 방법인데, 람다식은 이 익명 객체
내부에 존재하는 메서드라고 생각하면 된다. 따라서 (a, b) -> a > b ? a : b
라는 람다식은 다음과 같은 익명 객체
로 표현할 수 있다.
new Object() {
int max(int a, int b) {
return a > b ? a : b;
}
}
모든 클래스의 조상인 Object
타입을 사용해서 새로운 익명의 객체를 만들고, 그 내부에 람다식으로 표현을 할 메서드를 선언해준 형태를 가지고 있다. 자바에서는 객체를 다루기 위해 참조변수를 사용한다. 그래서 이 익명 객체
를 다루기 위한 참조변수까지 선언하면 다음과 같이 코드를 작성해볼 수 있다. 그리고 객체의 메서드를 사용하기 위해 .
을 이용해 max
메서드를 실행하려고 한다.
Object obj = new Object() {
int max(int a, int b) {
return a > b ? a : b;
}
}
obj.max(3, 5); // error: Cannot resolve method 'max' in 'Object'
그러나 실제로는 obj.max
를 사용할 수 없다. 오류가 나는 부분을 보면 Object
타입 내부에 max
라고 하는 메서드가 없다고 나온다. 즉, 우리가 익명 객체
를 만들면서 선언한 max
메서드는 실제 Object
타입에는 없는 것으로 볼 수 있다.
함수형 인터페이스
자바에서 익명 객체
내부에 선언된 메서드인 람다식을 정의하고 사용하기 위한 실제 방법은 함수형 인터페이스를 사용하는 것이다. 함수형 인터페이스는 단 하나의 추상 메서드를 가지고 있는 인터페이스를 의미하며, 사용방법은 다음과 같다.
// @FunctionalInterface 어노테이션을 사용하면 컴파일 단계에서 함수형 인터페이스 관련 오류를 잡을 수 있음
@FunctionalInterface
interface MyFunc {
int max(int a, int b);
}
// 함수형 인터페이스의 사용
MyFunc func = new MyFunc() {
@Override
public int max(int a, int b) {
return a > b ? a : b;
}
}
int maxVal = func.max(3, 5);
먼저 하나의 추상 메서드만을 가진 인터페이스인 MyFunc
을 정의해준다. 여기에서는 max
라는 메서드를 선언해주었다. 그리고 나서 실제 함수형 인터페이스를 사용하는 부분은 Object
타입의 익명 객체
를 사용하는 것과 완전히 동일하다. 중요한 차이는 참조변수의 타입이 MyFunc
와 같은 함수형 인터페이스이며, 생성되는 객체 역시 함수형 인터페이스를 조상으로 두는 클래스가 되어야 한다. 그리고 인터페이스의 구현체에는 인터페이스에서 정의한 메서드를 오버라이드 해야 하기 때문에 메서드의 구현부를 작성해주면 된다.
다시 람다식으로 돌아와서 아래와 같은 코드는 드디어 정상적으로 작동하게 된다. 람다식은 익명 객체
내부의 메서드로 표현될 수 있는데, 익명 객체
의 참조타입을 함수형 인터페이스로 선언할 수 있다면 (a, b) -> a > b ? a : b
와 같은 코드를 다음과 같이 사용할 수 있다.
MyFunc func = (a, b) -> a > b ? a : b;
int maxVal = func.max(3, 5);
'프로그래밍 언어 > Java' 카테고리의 다른 글
자바 8 람다식 해설서 - 2장 스트림과 함수형 인터페이스 (0) | 2022.12.21 |
---|---|
자바 8 람다식 해설서 - 1장 람다식 (0) | 2022.12.21 |
서블릿 필터 (0) | 2022.07.12 |
서블릿 (0) | 2022.07.05 |