Java/기본

[Java] 표준 함수형 인터페이스

댕주 2024. 10. 27. 16:54

표준 함수형 인터페이스는 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. 추가 메서드가 필요하다면 defaultstatic 으로 선언하기