자바(SE)

[람다표현식]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)  - 주로 parameterreturn 으로 매핑
: 새로운 타입으로 변환해서 리턴
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에서 많이 사용되고 있다. 기회가 되면..

 

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.