[람다표현식]functional interface
이번 포스트에서는 람다표현식의 짝궁인 functional package의 interface들에 대해 살펴보자.
java.util.functional
일반적인 의도(함수)의 전달
java는 객체지향 언어이다. 전통적으로 객체지향 언어에서는 의도만 따로 전달할 수 있는 방법이 없었다. 의도를 전달하기 위해서는 의도가 속한 클래스를 객체화 하고 거기서 정확한 메서드의 이름과 형태(구조: 파라미터, 리턴타입)가 중요하다.
하지만 함수형 프로그래밍에서는 의도를 직접 전달 할 수 있다! 이 함수는 이름이 필요없고 내용(실행문)만 필요한데 일반적으로 함수의 형태(구조)는 고정되어있다.
표준 함수형 인터페이스
자바 진영에서는 이런 함수형 프로그래밍 기법이 탐나서 람다식을 도입했는데 매번 의도를 전달할 때마다 @FunctionalInterface를 만들고 사용하기가 매우 번거로웠다. 따라서 표준화된 함수의 구조를 정의하고 사용할 수 있게 준비했는데 이것을 표준 함수형 인터페이스라고 부른다.
이 세상의 그 많고 많은 함수의 구조 즉 파라미터와 리턴 타입을 표준화 시킬 수 있었을까? 어렵게 생각할 필요가 전혀 없다. 그냥 파라미터가 있고 없고, 그에 따라서 리턴 타입이 있고 없고이다.
종류 | abstract method 특징 | |||
parameter | return | method | 비고 | |
java.lang.Runnable | X | X | void run() | Thread 용도 |
Consumer 계열 | O | X | void accept(T) | - 소비자 |
Supplier 계열 | X | O | T get() | - 공급자 |
Function 계열 | O | O | T apply (R) | - 주로 parameter를 return 으로 매핑 : 새로운 타입으로 변환해서 리턴 |
Operation 계열 | O | O | T XXX(R) | - 주로 parameter를 연산해서 return : 동일한 타입으로 연산 결과를 리턴 |
Predicate 계열 | O | boolean | boolean test(T) | - parameter를 조사해서 return 결정 |
이중 Runnable 만 java.lang에 속해있고 나머지는 java.util.function 패키지에 속해있다. 이들은 모두 @FunctionalInterface이기 때문에 하나의 abstract 메서드만 가지고 있으며 각각 파라미터와 리턴타입이 있거나 없다. 이제 여러분의 의도 즉 실행문만 작성해서 전달해주면 된다.
활용 예
간단한 활용 예를 통해서 함수형 인터페이스를 사용해보자.
다음은 java.util.Iterable의 forEach라는 메서드이다. forEach는 Consumer 타입을 받는다.
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
Consumer는 파라미터를 받고 리턴하지 않는다. 즉 소비만 하는데 List의 요소 하나 하나씩을 넘겨받아서 무엇을 할 것인지 의도만 작성하면 된다.
List<String> list = Arrays.asList("Hello", "Java", "World");
list.forEach(str -> System.out.println(str));
다음으로 java.util.Collection에 있는 removeIf 라는 메서드를 살펴보자. 이 메서드는 Predicate 타입을 인자로 받는다.
default boolean removeIf(Predicate<? super E> filter) {
Objects.requireNonNull(filter);
boolean removed = false;
. . .
return removed;
}
Predicate는 파라미터를 받고 리턴도 한는데 리턴 값의 타입은 boolean으로 정해져있다. 이제 필요한 것은 파라미터를 어떤 기준으로 삭제할 것인지에 대한 실행문이다.
List<String> list2 = new ArrayList<>();
list2.removeIf(item-> item.length()>2);
특히 이런 표준 함수형 인터페이스들은 람다와 함께 발표되시 시작한 Stream API에서 많이 사용되고 있다. 기회가 되면..