람다식(Lambda Expression)은 함수형 프로그래밍 기법을 지원하는 자바의 문법요소
람다식은 메서드를 하나의 ‘식(expression)’으로 표현한 것으로, 코드를 매우 간결하면서 명확하게 표현할 수 있다는 큰 장점이 있다.
//기존 메서드 표현 방식
void sayhello() {
System.out.println("HELLO!")
}
//위의 코드를 람다식으로 표현한 식
() -> System.out.println("HELLO!")
기본적으로 반환타입과 이름을 생략할 수 있다. 따라서 람다함수를 종종 이름이 없는 함수, 즉 익명 함수(anonymous function)라 부르기도 한다.
int sum(int num1, int num2) {
return num1 + num2;
}
(int num1, int num2) -> { // 반환타입과 메서드명 제거 + 화살표 추가
return num1 + num2;
}
반환타입과 메서드명을 제거하고 코드 블럭사이에 화살표를 추가
(int num1, int num2) -> { // 또한 반환값이 있는 메서드의 경우에는
// return문과 문장 뒤에 오는 세미콜론(;)을 생략할 수 있다.
num1 + num2
}
(int num1, int num2) -> num1 + num2
(num1, num2) -> num1 + num2
// sum 메서드 람다식
(num1, num2) -> num1 + num2
// 람다식을 객체로 표현
new Object() {
int sum(int num1, int num2) {
return num1 + num1;
}
}
sum
메서드는 사실 아래와 같은 익명 클래스. 익명 클래스란 객체의 선언과 생성을 동시에 하여 오직 하나의 객체를 생성하고, 단 한번만 사용되는 일회용 클래스이다.new Object() { //익명 클래스
int sum(int num1, int num2) {
return num1 + num1;
}
}
람다식이 객체라 한다면 이 객체에 접근하고 사용하기 위한 참조변수가 필요하다.그런데 기존에 객체를 생성할 때 만들었던 Object
클래스에는 sum
이라는 메서드가 없기 때문에, Object
타입의 참조변수에 담는다고 하더라도 sum
메서드를 사용할 수 없다. 이 같은 문제를 해결하기 위해 사용하는 자바의 문법 요소가 바로 자바의 함수형 인터페이스(Functional Interface)라 할 수 있다.
기존의 인터페이스 문법을 활용하여 람다식을 다루는 것인데, 이것이 가능한 이유는 람다식도 결국 하나의 객체이기 때문에 인터페이스에 정의된 추상메서드를 구현할 수 있기 때문이다.
함수형 인터페이스에는 단 하나의 추상 메서드만 선언될 수 있는 데, 람다식과 인터페이스의 메서드가 1:1로 매칭되어야 하기 때문이다.
@FunctionalInterface
public interface MyFunctionalInterface {
public void accept();
}
accept()
가 매개변수를 가지지 않기 때문이다.MyFunctionalInterface example = () -> { ... };
// example.accept();
accept()
를 호출할 수 있다. accept()
의 호출은 람다식의 중괄호 {}
를 실행시킨다.accept()
의 매개변수가 하나이기 때문이다.@FunctionalInterface
public interface MyFunctionalInterface {
public void accept(int x);
}
accept()
가 리턴 타입이 있기 때문에 중괄호 { }
에는 return 문이 있어야 한다.@FunctionalInterface
public interface MyFunctionalInterface {
public int accept(int x, int y);
}
(left, right) -> Math.max(left, right);
// 아래의 형태로 깔끔하게 처리 가능
// 클래스이름::메서드이름
Math :: max; // 메서드 참조
::
기호를 붙이고 정적 메서드 이름을 기술하면 된다.클래스 :: 메서드
::
기호를 붙이고 인스턴스 메서드 이름을 기술하면 된다.참조 변수 :: 메서드
//Calculator.java
public class Calculator {
public static int staticMethod(int x, int y) {
return x + y;
}
public int instanceMethod(int x, int y) {
return x * y;
}
}
import java.util.function.IntBinaryOperator;
public class MethodReferences {
public static void main(String[] args) throws Exception {
IntBinaryOperator operator;
/*정적 메서드
클래스이름::메서드이름
*/
operator = Calculator::staticMethod;
System.out.println("정적메서드 결과 : " + operator.applyAsInt(3, 5));
/*인스턴스 메서드
인스턴스명::메서드명
*/
Calculator calculator = new Calculator();
operator = calculator::instanceMethod;
System.out.println("인스턴스 메서드 결과 : "+ operator.applyAsInt(3, 5));
}
}
(a,b) -> {return new 클래스(a,b);};
//생성자 참조 문법
클래스 :: new
public class ConstructorRef {
public static void main(String[] args) throws Exception { // Member 클래스
Function<String, Member> function1 = Member::new;
Member member1 = function1.apply("kimcoding");
BiFunction<String, String, Member> function2 = Member::new;
Member member2 = function2.apply("kimcoding", "김코딩");
}
}