Functional Interface는 함수를 *일급 객체로 사용할 수 없는 Java 언어의 단점을 보완하기 위해 도입되었다.

JDK 1.8의 java.util.function 패키지에는 수많은 Functional Interface들이 정의되어 있다.

 

*일급 객체 ( first-class object )

다른 객체들에 일반적으로 적용 가능한 연산을 모두 지원하는 객체를 가르킨다.

보통 함수에 매개변수로 넘기기, 수정하기, 변수에 대입하기와 같은 연산을 지원할 때 일급 객체라고 한다.

(참고: https://ko.wikipedia.org/wiki/%EC%9D%BC%EA%B8%89_%EA%B0%9D%EC%B2%B4)

 

"API 문서의 설명"

This is a functional interface and can therefore be used as the assignment target for a lambda expression or method reference.

 

해당 포스팅에서 아래의 3가지를 정리해보자.

  1. Functional Interface란?
  2. java.util.function 패키지의 대표적인 인터페이스
  3. 위 인터페이스를 사용하는 java.util.stream.Stream 인터페이스에 람다식을 적용하는 방법

1. Functional Interface

Functional Interface메서드를 하나만 가지는 인터페이스를 말한다.

 

"Java Language Specification의 설명"

functional interface is an interface that has just one abstract method (aside from the methods of Object), and thus represents a single function contract.

 

위의 설명에서 Object 클래스를 제외하고 라는 문구가 있는데, 이는 모든 객체가 Object 객체를 상속받는 Java의 특징 때문이다.

메서드를 하나만 가지는 인터페이스를 함수형 인터페이스라고 그냥 부를 수도 있지만, 의미를 좀 더 명확히 함과 더불어 해당 인터페이스가 Function Interface라는걸 명시하여 메서드를 추가로 선언하거나 인터페이스를 상속받는 등의 부적절한 행동을 미연에 방지하기 위해 @FunctionalInterface 어노테이션을 사용한다.

 

 

Lamda와 Functional Interface에 대해 설명된 Java 명세를 살펴보자.

"Java Language Specification의 설명"

A lambda expression is like a method: it provides a list of formal parameters and a body - an expression or block - expressed in terms of those parameters.

- 중략 -

Evaluation of a lambda expression produces an instance of a functional interface (§9.8). Lambda expression evaluation does not cause the execution of the expression's body; instead, this may occur at a later time when an appropriate method of the functional interface is invoked.

 

람다식의 평가 결과는 Functional Interface의 인스턴스다 !

산수 연산을 표현하는 ArithmeticOperator를 사용한 예제를 살펴보자.

@FunctionalInterface
public interface ArithmeticOperator {
    public int operate(int a, int b);
}

 

@FunctionalInterface
public class ArithmeticCalculator {
    public static int calculate(int a, int b, ArithmeticOperator operator) {
        return operator.operate(a, b);
    }
}

 

public class ArithmeticCalculatorTest {

    @Test
    public void test() {
        int first = 5;
        int second = 10;
        
        int result = ArithmeticCalculator.calculate(first, second, (a, b) -> a + b);
        Assert.assertEquals(first + second, result);
    }
}

 

위의 ArithmeticCalculatorTest#test 메서드를 보면, ArithmeticOperator의 구현체가 예상되는 곳에 람다식을 넣었다.

Functional Interface는 추상 메서드가 하나뿐이기 때문에 파라미터와 리턴 타입을 쉽게 추론할 수 있고, 이를 근거로 인스턴스를 생성한다.

 

2. java.util.function 패키지의 대표적인 인터페이스

해당 패키지에서 대표적으로 사용되는 Functional Interface는 네 가지다.

아래처럼 일반적인 경우에 대해 미리 Functional Interface를 만들어 제공함으로써 코딩의 일관성을 부여할 수 있다.

 

java.util.function 패키지에 들어있는 Functional Interface

 

 

3. Functional Interface Example with Stream

(참고: https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html#approach3)

Functional Interfacejava.util.stream.Stream과 함께 사용하게되면 코드를 아주 간결하고 깔끔하게 만들 수 있다.

enum 타입을 예로 들어보자.

public enum Color {

    COLOR_RED(0, "red"),
    COLOR_GREEN(1, "green"),
    COLOR_BLUE(2, "blue"),
    COLOR_NONE(3, "none");
    
    Color(Integer number, String type) { 
        this.number = number; 
        this.type = type;
    }
    
    @Getter Integer number;
    @Getter String type;
    
    private static Color find(Predicate<Color> predicate) {
        return Arrays.stream(values())
                 .filter(predicate)
                 .findAny()
                 .orElse(COLOR_NONE);
    }
    
    public Color fromNumber(Integer number) {
        return find(e -> e.number == number);
    }
    
    public Color fromType(String type) {
        return find(e -> Objects.equals(e.type, type));
    }
}

 

 

 

참고자료

[1] https://beomseok95.tistory.com/277

 

 

'Programming > Java' 카테고리의 다른 글

[Java] @ 어노테이션  (0) 2020.03.31
[Java] Optional<T> 클래스  (0) 2020.03.24
[Java] 메서드 참조 ( Method Reference )  (0) 2020.03.24
[Java] .jar와 .war  (0) 2020.03.20
[Java] 람다와 스트림 ( Lambda, Stream )  (0) 2020.03.05