ksouth9

람다식(Lambda expression)(2) 본문

Java

람다식(Lambda expression)(2)

ksouth9 2022. 4. 16. 19:44

함수형 인터페이스(Functional Interface)


자바의 람다식은 함수형 인터페이스로만 사용이 가능하다.

함수형 인터페이스를 사용하는 이유는 람다식은 함수형 인터페이스로만 접근이 가능하기 때문이다. 인터페이스의 참조변수로 람다식의 메서드를 호출 할 수 있다. 

 

예시

interface MyFunction {
	public abstract int max(int a, int b);
}

MyFunction f = new MyFunction {
	public int max(int a, int b) {
    	return a > b ? a : b;
        }
};
int big = f.max(5, 3)	// 익명 객체의 메서드를 호출

MyFunction 인터페이스에 정의된 메서드 max()는 람다식 '(int a, int b) -> a > b ? a : b'과 메서드의 선언부가 일치한다. 그러므로 익명 객체를 람다식으로 아래와 같이 대체할 수 있다.

MyFunction f = (int a, int b) -> a > b ? a : b;	// 익명 객체를 람다식으로 대체
int big = f.max(5, 10);	// 익명 객체의 메서드를 호출

MyFunction 인터페이스를 구현한 익명 객체를 람다식으로 대체가 가능한 이유는, 람다식도 실제로는 익명 객체이고, MyFunction 인터페이스를 구현한 익명 객체의 메서드 max()와 람다식의 매개변수의 타입과 개수 그리고 반환값이 일치하기 때문이다. 

 

람다식을 다루기 위한 인터페이스를 '함수형 인터페이스(functional interface)'라고 부른다.

@FunctionalInterface
interface MyFunction {	// 함수형 인터페이스 MyFunction을 정의
	public abstract int max(int a, int b);
}

단, 함수형 인터페이스에는 오직 하나의 추상 메서드만 정의되어 있어야 한다는 제약이 있다. 그래야 람다식과 인터페이스의 메서드가 1:1로 연결될 수 있기 때문이다. 반면에 static메서드와 default메서드의 개수에는 제약이 없다.

※@FunctionalInterface를 붙이면, 컴파일러가 함수형 인터페이스를 올바르게 정의하였는지 확인해준다.

 

함수형 인터페이스 타입의 매개변수와 반환타입

함수형 인터페이스 MyFunction이 아래와 같이 정의되어 있을 때,

@FunctionalInterface
interface MyFunction {
	void myMethod();	// 추상 메서드
}

메서드의 매개변수가 MyFunction타입이면, 이 메서드를 호출할 때 람다식을 참조하는 참조변수를 매개변수로 지정해야한다.

void aMethod(MyFunction f) {	// 매개변수의 타입이 함수형 인터페이스
	f.myMethod();	// MyFunction에 정의된 메서드 호출
}

MyFunction f = () -> System.out.println("myMethod()");
aMethod(f);

또는 참조변수 없이 아래와 같이 직접 람다식을 매개변수로 지정하는 것도 가능하다.

aMethod(() -> System.out.println("myMethod()")));	// 람다식을 매개변수로 지정

그리고 메서드의 반환타입이 함수형 인터페이스타입이라면, 이 함수형 인터페이스의 추상메서드와 동등한 람다식을 가리키는 참조변수를 반환하거나 람다식을 직접 반환할 수 있다.

MyFunction myMethod() {
	MyFunction f = () -> {};
    return f;
    // 위의 두줄을 한 줄로 줄이면, return () -> {};
}

람다식을 참조변수로 다룰 수 있다는 것은 메서드를 통해 람다식을 주고받을 수 있다는 것을 의미한다. 변수처럼 메서드를 주고받는 것이 가능해진 것이다.

@FunctionalInterface
interface MyFunction {
	void run();	// public abstract void run();
}
class LambdaEx1 {
	static void execute(MyFunction f) {	// 매개변수의 타입이 MyFunction인 메서드
		f.run();
	}
	static MyFunction getMyFunction() {
		MyFunction f = () -> System.out.println("f3.run()");
		return f;
	}
	public static void main(String[] args) {
		// 람다식으로 MyFunction의 run()을 구현
		MyFunction f1 = () -> System.out.println("f1.run()");
		
		MyFunction f2 = new MyFunction() {	// 익명클래스로 run()을 구현
			public void run() {	// public을 반드시 붙여야 함
				System.out.println("f2.run()");
			}
		};
		MyFunction f3 = getMyFunction();
		
		f1.run();
		f2.run();
		f3.run();
		
		execute(f1);
		execute(() -> System.out.println("run()"));
	}
	
}//실행결과
f1.run()
f2.run()
f3.run()
f1.run()
run()

'Java' 카테고리의 다른 글

입출력 I/O(2) - 바이트기반 스트림  (0) 2022.04.17
입출력 I/O(1)  (0) 2022.04.17
람다식(Lambda expression)(1)  (0) 2022.04.11
java.util.StringTokenizer 클래스  (0) 2022.04.06
java.util.Scanner 클래스  (0) 2022.04.05