함수형 인터페이스는 정확히 하나의 추상 메서드를 지정하는 인터페이스다.
디폴트 메서드(Default Method)가 있더라도 추상 메서드가 오직 하나면 함수형 인터페이스다.
JDK 8부터 도입된 디폴트 메서드(Default Method)는 인터페이스 내부에서도 로직을 갖는 메서드를 포함할 수 있다.
// 함수형 인터페이스 Consumer
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
람다 표현식을 통해 함수형 인터페이스 추상 메서드 구현을 직접 전달할 수 있고, 전체 표현식을 함수형 인터페이스 인스턴스로 취급할 수 있다.
기존 익명 클래스(Anonymous Class)도 이와 같은 기능을 구현할 수 있다.
함수형 인터페이스의 인스턴스로 취급
람다 표현식은 어떠한 함수형 인터페이스를 구현하는지 정보를 포함하지 않는다.
함수형 인터페이스는 @FunctionalInterface
애노테이션을 인터페이스 상위에 지정하여 사용하지만,
추상 메서드가 하나인 경우 애노테이션이 없더라도 함수형 인터페이스로 취급된다.
애노테이션을 명시적으로 선언하는 경우, 함수형 인터페이스가 아니면 컴파일 에러를 발생시킨다.
// Functional Interface
public interface FpAdder {
int add( int a, int b );
}
// Functional Interface 가 아님
//@FunctionalInterface // : 컴파일 에러 발생
public interface ExtAdder extends FpAdder {
int add( long a, long b );
}
// Functional Interface 가 아님
public interface NothingAdder {
}
함수형 인터페이스의 추상 메서드 시그니처(Signature)는 람다 표현식의 시그니처를 가리킨다.
람다 표현식의 시그니처를 서술하는 메서드를 함수 디스크립터
라고 한다.
public interface FpAdder {
int add( int a, int b );
}
// int, int -> int
public interface Consumer<T> {
void accept(T t);
}
// T -> void
Java 8 in Action (2014) - Raoul-Gabriel Urma, Mario Fusco, and Alan Mycroft