이펙티브 자바의 아이템44. '표준 함수형 인터페이스를 사용하라' 부분을 읽고 정리하는 포스팅.✍️
아이템44 표준 함수형 인터페이스 정리
함수형 인터페이스란?
오직 하나의 추상 메소드만 저장하는 인터페이스. 필드 메소드를 파라미터화 할 수 있음.
많은 디폴트 메소드가 있더라도 추상 메소드가 오직 하나면 함수형 인터페이스다.
@FunctionalInterface를 붙이지 않아도 추상 메서드가 한개면 함수형 인터페이스이다.
ex)
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
// ...
}표준 함수형 인터페이스를 사용하라.
꼭 필요한게 아니라면, 굳이 함수형 인터페이스를 정의하지 말자.
필요한 용도에 맞는 게 있다면, 직접 구현하지 말고 표준 함수형 인터페이스를 활용하라
자바의 표준 함수형 인터페이스
(5가지 기본 함수형 인터페이스 + 파생 함수형 인터페이스)
Consumer
메서드: accept
시그니처: (T) -> void
파생된 함수형 인터페이스 정리
| 인터페이스 | 시그니처 | 메서드 |
|---|---|---|
| BiConsumer | (T, U) -> void | accept |
| IntConsumer | (int) -> void | accept |
| LongConsumer | (long) -> void | accept |
| DoubleConsumer | (double) -> void | accept |
| ObjIntConsumer | (T, int) -> void | accept |
| ObjLongConsumer | (T, long) -> void | accept |
| ObjDoubleConsumer | (T, double) -> void | accept |
Supplier
메서드: get
시그니처: () -> R
파생된 함수형 인터페이스 정리
| 인터페이스 | 시그니처 | 메서드 |
|---|---|---|
| BooleanSupplier | void -> boolean | getAsBoolean |
| IntConsumer | void -> int | getAsInt |
| LongConsumer | void -> long | getAsLong |
| DoubleConsumer | void -> double | getAsDouble |
Operator 계열
메서드: apply
함수형 인터페이스 정리
| 인터페이스 | 시그니처 | 메서드 |
|---|---|---|
| UnaryOperatior | (T) -> T | apply |
| BinaryOperator | (T, T) -> T | apply |
| IntUnaryOperatior | (int) -> int | applyAsInt |
| LongUnaryOperatior | (long) -> long | applyAsLong |
| DoubleUnaryOperatior | (double) -> double | applyAsDouble |
| IntBinaryOperatior | (int, int) -> int | applyAsInt |
| LongBinaryOperatior | (long, long) -> long | applyAsLong |
| DoubleBinaryOperatior | (double, double) -> double | applyAsDouble |
Predicate계열
메서드: test
시그니처: (T) -> boolean
함수형 인터페이스 정리
| 인터페이스 | 시그니처 | 메서드 |
|---|---|---|
| BiPredicate | (T, U) -> boolean | test |
| IntPredicate | (int) -> boolean | test |
| LongPredicate | (long) -> boolean | test |
| DoublePredicate | (double) -> boolean | test |
Function계열
메서드: apply
시그니처: (T) -> R
파생된 함수형 인터페이스 정리
| 인터페이스 | 시그니처 | 메서드 |
|---|---|---|
| BiFunction | (T, U) -> R | apply |
| IntFunction | (int) -> R | apply |
| LongFunction | (long) -> R | apply |
| DoubleFunction | (double) -> R | apply |
| ToIntFunction | (T) -> int | applyAsInt |
| ToLongFunction | (T) -> long | applyAsLong |
| ToDoubleFunction | (T) -> double | applyAsDouble |
| {T}To{R}Function | (T) -> R | applyAs{R} |
| To{R}BiFunction | (T, U) -> R | applyAs{R} |
참고: 모던 자바 인 액션
주의할 점
- 표준 함수형 인터페이스는 총 43가지로 다 외울 필요는 없다. 규칙성도 모호함.
- 표준 함수형 인터페이스는 주로 기본타입형 특화로 지원하는데, 박싱된 기본타입을 넣어서 사용하지 말것. 계산량이 많을 경우 성능이 처참히 느려진다.
@FunctionalInterface를 쓰는 이유는@Override를 붙이는 이유와 비슷하다. 이게 함수형 인터페이스라고 나타내기 위함과 동시에 추상 메서드를 오직 하나만 가지도록 컴파일러가 인식하게 한다.
ex)

- 직접 만든 함수형 인터페이스에는 반드시
@FunctionalInterface를 붙여서 사용할 것. - 함수형 인터페이스를 같은 위치의 인수로 받는 메서드들을 다중 정의(오버로드)하면 안된다. 클라이언트에게 모호함을 안겨줄 뿐더러 인터페이스의 시그니처가 같으면 람다로 인수를 넘겨줄 수도 없다.
public class Test {
public void test(TestInterface t) {
t.test1();
}
public void test(TestInterface2 t2) {
t2.test2();
}
// 시그니처가 같아서 람다식으로 인수를 전달할 수 없고, 직접 형변환하여 인수를 넘겨줄 수 있음
}'Java' 카테고리의 다른 글
| 멤버 클래스는 되도록 static으로 (2) | 2022.03.30 |
|---|---|
| Stream.forEach() vs for-each (0) | 2022.03.14 |
| Collections.unmodifiableXX()는 방어적 복사가 아니다 (1) | 2022.03.06 |
| Collection의 깊은 복사와 방어적 복사 (2) | 2022.03.05 |
| 추상 클래스와 인터페이스의 용도 차이 (0) | 2022.03.03 |