본문 바로가기
Programming/Java, Spring

자바의 Functional Interface와 andThen 메서드 이해하기

by Renechoi 2023. 6. 2.

 

 

1. Function interface 

 

@FunctionalInterface
public interface Function<T, R> {
  R apply(T t);
}

 

input 타입은 T 이고 return 타입은 R인 메서드 

 

이것을 Object 형태로 구현하면 어떻게 될까? 아래처럼 쓸 수 있다. 

 

public class Adder implements Function<Integer, Integer> {
   @Override
   public Integer apply(Integer integer) {
      return integer + 10;
   }
}
public static void main(String[] args) {

   Function<Integer, Integer> adder = new Adder();
   Integer apply = adder.apply(5);
   System.out.println("apply = " + apply);

}

 

 

그런데 이러한 방식은 상당히 거추장 스럽다. 매번 객체를 만들어주고 반환해주는 메서드를 사용해야 한다. 

 

만약 더하기 action이 10번 있다면 매번 객체를 만들고 메서드를 소환해야 할까? 

 

람다식으로 이 문제를 해결할 수 있다. 

 

(Integer x) -> { return x + 10; }

 

다음과 같이 선언과 동시에 구현해주고 리턴을 받는다. 

Function<Integer, Integer> adder2 = (Integer x) -> { return x + 10; };

 

 

- 매개 변수의 타입이 유추 가능할 경우 타입 생략 가능

- 매개 변수가 하나일 경우 괄호 생략 가능

- 바로 리턴하는 경우 중괄호 생략 가능 

 

Function<Integer, Integer> adder2 = (Integer x) -> x + 10;
Function<Integer, Integer> adder2 = x -> x + 10;

즉 클래스를 만들 필요 없이 바로 동작을 구현할 수 있다. 

 

 

 

 

2. BiFunction Interface 

 

만약 두 개의 변수를 받고 싶다면 어떡할까? 

 

BiFunction Interface는 두 개의 파라미터를 받아 R을 리턴한다. 

@FunctionalInterface
public interface BiFunction<T, U, R> {
   R apply(T t, U u);
}

 

BiFunction<Integer, Integer, Integer> add = (x, y) -> { return x + y;};

 

 

그렇다면 3개를 받으려면 어떻게 해야할까? 

 


Functional Interface 

- 단 하나의 abstract method 만을 가지는 인터페이스 (Sigle Abstract Method interface)

- Default method와 static method는 이미 구현이 되어 있기 때문에 카운팅 되지 않는다. 

 

 

이를 이용해 trifunction interface를 만들 수 있다. 

 

@FunctionalInterface
public interface TriFunction<T, U, V, R> {
   R apply(T t, U u, V v);
}
public static void main(String[] args) {
    TriFunction<Integer, Integer, Integer, Integer> sum = (a, b, c) -> a + b + c;

    int result = sum.apply(1, 2, 3);
    System.out.println(result);  // 출력: 6
}

 

 


3. andThen 메서드

 

 

Java의 함수형 인터페이스는 andThen 메서드를 사용하여 함수를 연결할 수 있다.

이를 통해 함수들을 연속적으로 실행할 수 있다.


andThen 메서드는 함수형 인터페이스에서 제공되는 default 메서드로, 해당 인터페이스를 구현한 클래스에서 사용할 수 있다. 현재 함수를 실행한 후 다른 함수를 실행하도록 체인 형태로 연결할 수 있게 해준다. 체인의 순서는 andThen 메서드를 호출하는 순서이다.

 

다음과 같은 Functional Interface와 andthen method를 구현했다. 

 

 

@FunctionalInterface
interface Function<T, R> {
    R apply(T t);

    default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t) -> after.apply(apply(t));
    }
}

이 코드에서 Function 인터페이스는 제네릭 타입 T와 R을 가지며, apply 메서드를 선언하고 있다.

apply 메서드는 입력값 T를 받아 결과값 R을 반환하는 추상 메서드이다.


해당 인터페이스는 andThen이라는 default 메서드를 갖는다. andThen 메서드는 현재 Function 객체를 실행한 후 다른 Function 객체를 실행하도록 체인 형태로 연결할 수 있게 해주는 것이다. 

 

andThen 메서드의 시그니처를 해석해보자. 

 

위의 시그니처에서 ? super R은 after 함수의 입력 매개변수가 R 또는 R의 상위 타입이라는 것을 의미한다. 마찬가지로 ? extends V는 after 함수의 반환 타입이 V 또는 V의 하위 타입이라는 것을 의미한다.

 

즉, andThen 메서드는 함수 자체를 입력 값으로 받는다.

 

이후 현재 함수를 실행한 후 after 함수를 실행하도록 체인 형태로 연결해주는 역할을 한다. 반환되는 함수는 입력 타입 T를 받아 먼저 현재 함수를 적용한 후 그 결과를 after 함수에 입력하여 최종 결과를 반환한다.

 

 

 

 

이 인터페이스를 사용 예시는 다음과 같다. 

 

public static void main(String[] args) {

   Function<Integer, Integer> multiplyByTwo = (x) -> x * 2;
   Function<Integer, Integer> addOne = (x) -> x + 1;

   Function<Integer, Integer> multiplyAndAdd = multiplyByTwo.andThen(addOne);

   // 입력 3에 대해 multiplyByTwo 함수를 실행한 후 addOne 함수를 실행한다.
   int result = multiplyAndAdd.apply(3); 

   System.out.println(result); // 출력: 7 (3 * 2 + 1)
}
반응형