JAVA

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

jhkimmm 2022. 1. 3. 01:11

람다식에 대해 잘 모른다면 아래 포스팅을 참고하길 바랍니다.

 

[JAVA] 람다식 Lambda Expression

JDK1.8 부터 추가된 람다식은 자바를 객체지향언어인 동시에 함수형 언어가 될 수 있게 해주었습니다. 람다식 덕분에 자바는 기존의 자바를 거의 변경하지 않고도 함수형 언어의 장점을 잘 접목

jhkimmm.tistory.com

 

람다식에 대한 기본적인 내용을 학습했다면, 일반적으로 자주 쓰이는 형식의 메서드를 함수형 인터페이스로 미리 정의해 놓은 java.util.function 패키지에 대해서 알아보아야 합니다. 매번 새로운 함수형 인터페이스를 정의한다면 재사용성이나 유지보수 측면에서 좋지 않으므로, 가능하면 이 패키지의 인터페이스를 사용하는 것이 좋습니다.

가장 기본적인 함수형 인터페이스

함수형 인터페이스 메서드 설명
java.lang.Runnable void run() 매개변수X, 반환값X
Supplier<T> T get() 매개변수X, 반환값O
Consumer<T> void accept(T) 매개변수O, 반환값X
Function<T, R> R apply(T t) 매개변수O, 반환값O
Predicate<T> boolean test(T t) 매개변수O, 반환값은 boolean

매개변수와 반환값의 유무에 따라 4개의 함수형 인터페이스가 정의되어 있습니다.

Predicate는 Function의 변형인데 반환값이 boolean이란 것만 제외하면 동일합니다. Predicate는 조건식을 람다식으로 표현하는데 사용됩니다.

기본형을 사용하는 함수형 인터페이스

함수형 인터페이스 메서드 설명
DoubleToIntFunction int applyAsInt(double d) AToBFunction은 입력이 A타입이고 출력이 B타입이다.
ToIntFunction<T> int applyAsInt(T value) ToBFunction은 입력이 지네릭 타입이고 출력이 B타입이다.
IntFunction<R> R apply(int i) AFunction은 입력이 A타입이고 출력이 지네릭 타입
ObjIntConsumer<T> void accept(T t, int i) objAFunction은 입력이 지네릭 타입과 A타입이고 출력은 없다.

매개변수와 반환값의 타입이 모두 지네릭 타입이라면 기본형 값을 처리할 때도 래퍼 클래스를 사용해야 하므로 비효율 적입니다. 그래서 보다 효율적인 처리를 위해 기본형을 사용하는 함수형 인터페이스가 제공됩니다.

매개변수가 두 개인 함수형 인터페이스

함수형 인터페이스 메서드 설명
BiConsumer<T, U> void accept(T t, U u) 매개변수 2개, 반환값X
BiPredicate<T, U> boolean test(T t, U u) 매개변수 2개, 반환값 boolean
BiFunction<T,U,R> R apply(T t, U u) 매개변수 2개, 반환값 1개

매개변수가 2개인 함수형 인터페이스는 이름 앞에 접두사 Bi가 붙으며, Supplier는 반환값만 존재하는데 메서드는 두 개의 값을 반환할 수 없으므로 BiSupplier는 없습니다.

매개변수가 3개 이상이면 직접 만들어써야 하는데 매개변수가 3개인 Function을 구현해보면 다음과 같습니다.

@FunctionalInterface
interface Function<T,U,V,R>
	R apply(T t, U u, V v);
}

UnaryOperator와 BinaryOperator

함수형 인터페이스 메서드 설명
UnaryOperator<T> T apply(T t) Function의 자손이지만
Function과 달리 매개변수와 반환값의 타입이 같다
BinaryOperator<T> T apply(T t, T t) BiFunction의 자손이지만
BiFunction과 달리 매개변수와 결과의 타입이 같다.

사용 예시

기본 함수형 인터페이스 Consumer와 기본형을 사용하는 함수형 인터페이스인 IntFunction이 사용되는 간단한 예시를 만들어 보겠습니다. 1~10사이의 랜덤한 정수값을 배열에 담고 이를 리스트로 변환한 후 콘솔에 출력하는 예제입니다.

ArrayList list;
Integer[] arr = new Integer[5];
Arrays.setAll(arr, (i) -> (int)(Math.random()*10+1) );//1~10사이의 랜덤값 배열에 저장
list = new ArrayList(Arrays.asList(arr)); //배열을 리스트로 변환
list.forEach(x -> System.out.println(x)); //리스트에 저장된 값 출력

setAll 메서드의 시그니처

Arrays.setAll 메서드는 왼쪽에서 확인할 수 있듯이 IntFunction타입 함수형 인터페이스의 참조변수를 매개변수로 가지고 있으므로 람다식을 매개변수로 넘겨주어야 합니다. 그러므로 Interger배열인 arr에 1에서 10사이의 랜덤 값을 넣어주는 람다식 (i) -> (int)(Math.random()*10+1)을 넘겨주었습니다.

forEach 메서드의 시그니처

forEach메서드는 Consumer를 매개변수로 받으므로 람다식 x -> System.out.println(x)을 넘겨주어 리스트의 내용을 콘솔에 출력하였습니다.

※사실 list.forEach(x->System.out.println(x));는 메서드 참조를 이용하여 list.forEach(System.out::println);으로 더욱 간단하게 사용할 수 있지만 메서드 참조에 대해서는 다음번에 포스팅 하겠습니다.