표준 함수형 인터페이스는 Java에서 자주 사용하는 기본적인 함수 형태를 미리 정의해 둔 인터페이스들로, java.util.function 패키지에 포함되어 있다. 얘네들은 람다와 메서드 참조를 더 간편하게 사용할 수 있도록 도와주는 착한 친구들이라고 보면 된다.
이런 인터페이스들은 주로 메서드가 하나만 있는 함수형 인터페이스고, 입력과 출력의 형태에 따라 적절한 이름과 구조를 가지고 있다.
종류
1. Function<T, R>: 입력값 T를 받아 출력값 R을 반환하는 함수
메서드: R apply(T t)
예시: 문자열을 받아 길이를 반환
Function<String, Integer> lengthFunction = s -> s.length();
lengthFunction.apply("Java"); // 4
2. Consumer<T>: 입력값 T를 받아 처리만 하고 반환값이 없는 함수
메서드: void accept(T t)
예시: 문자열을 출력
Consumer<String> printConsumer = s -> System.out.println(s);
printConsumer.accept("Hello"); // Hello
3. Suppler<T>: 입력값 없이 값을 반환하는 함수
메서드: T get()
예시: 현재 시간을 반환
Supplier<Long> currentTimeSupplier = () -> System.currentTimeMillis();
currentTimeSupplier.get(); // 현재 시간(밀리초)
4. Predicate<T>: 입력값 T를 받아 boolean을 반환하는 조건 검사 함수
메서드: boolean test(T t)
예시: 문자열이 비어있는지 검사
Predicate<String> isEmptyPredicate = s -> s.isEmpty();
isEmptyPredicate.test(""); // true
5. UnaryOperation<T>: 입력값 T를 받아 동일한 타입 T를 반환하는 함수로, Function<T, T>와 동일하지만, 입력과 출력 타입이 동일할 때 사용
메서드: T apply(T t)
예시: 숫자를 제곱하는 함수
UnaryOperation<Integer> square = x -> x * x;
square.apply(5); // 25
6. BinaryOperation<T>: 두 개의 동일한 타입 T 입력을 받아 T 타입의 결과를 반환하는 함수로, BiFunction<T, T, T>와 동일한 형태
메서드: T apply(T t1, T t2)
예시: 두 숫자를 더하는 함수
BinaryOperation<Integer> add = (x,y) -> x + y;
add.apply(3, 5); // 8
7. BiFunction<T, U, R>: 두개의 입력값 T와 U를 받아 결과값 R을 반환하는 함수
메서드: R apply(T t, U u)
예시: 두 문자열을 결합하는 함수
BiFunction<String, String, String> concat = (s1, s2) -> s1 + s2;
concat.apply("Hello, ", "World!"); // Hello, World!
장점
- 재사용성: 자주 사용하는 함수의 형태를 미리 정의해 두어 코드가 간결하고 재사용 가능하게 만든다
- 가독성: 함수형 인터페이스의 이름만으로 함수의 목적을 쉽게 알 수 있다
- 호환성: 람다 표현식과 메서드 참조와 결합하여 더욱 직관적인 코드를 작성할 수 있다
단점
- 가독성: 표준 함수형 인터페이스와 람다를 남용하면 코드가 지나치게 축약되어서 의도 파악이 어렵다
- 오류 처리: 검사 예외(Checked Exception)를 처리하기 어렵다. Function<T, R>을 사용할 때, 예외를 던지는 메서드를 호출해야 한다면 람다 내부에서 try - catch 를 넣어야 한다. 특히 Streams API 와 결합해서 사용할 때 예외처리가 힘들다.
- 디버깅: 일반 메서드와 달리 스택 추적을 통해 문제 분석이 어렵다
- 직관성: 단순 연산에 적합하지만, 복잡한 로직을 람다로 표현하면 명확성이 떨어진다.
표준 함수형 인터페이스를 직접 만들 수도 있을까?
Yes
함수형 인터페이스는 메서드가 하나만 있는 인터페이스로 정의되고, @FunctionalInterface 어노테이션을 붙여 하나의 추상 메서드만 정의되도록 강제할 수 있다.(그러니까 무조건 붙여주자 별5개)
이 어노테이션을 붙이면 컴파일러가 메서드 수를 검사하기 때문에 실수로 메서드를 추가해 함수형 인터페이스가 되지 않는 상황을 예방할 수 있다.
@FunctionalInterface
interface MathOperation {
int operate(int a, int b);
}
public class Main {
public static void main(String[] args) {
MathOperation plus = (a, b) -> a + b;
MathOperation minus = (a, b) -> a - b;
plus.operate(5, 3); // 8
minus.operate(5, 3); // 2
}
}
주의 사항
1. @FunctionalInterface 어노테이션 붙이기
2. 단일 추상 메서드만 정의하기.
2-1. 추가 메서드가 필요하다면 default 나 static 으로 선언하기
'Java > 기본' 카테고리의 다른 글
[Java] Java에서 final로 진짜_최종_최종_최종 불변 객체 만들기 (0) | 2024.10.31 |
---|---|
[Java] Java에서 final로 불변 객체 만들기 (0) | 2024.10.30 |
[Java] 스트림(Stream) (0) | 2024.10.27 |
[Java] 메서드 참조 (0) | 2024.10.27 |
[Java] 추상 클래스 (0) | 2024.10.27 |