IT

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

data-cloud 2025. 1. 22. 22:07
반응형

 


이전 포스팅에서 람다식(Lambda Expressions)에 대해서 간략하게 알아보았다.

이번 포스팅에서는 람다식과 밀접한 관련이 있는 함수형 인터페이스에 대해서 알아보도록 하자.

 

 

 

☕️ 함수형 인터페이스(Functional Interface)란?

함수형 인터페이스란 오로지 1개의 추상 메서드만을 갖는 인터페이스를 말한다.
(* Default Method와 Static Method의 개수는 상관이 없다.)

 

 

 

☕️ 함수형 인터페이스의 선언과 활용

함수형 인터페이스는 아래와 같은 형태로 만들 수 있다.

@FunctionalInterface
interface SquareIF {
    int square(int num);
}

이때, 함수형 인터페이스를 나타내기 위해 @FunctionalInterface 어노테이션을 사용할 수 있다.  이 어노테이션을 사용하게 되면 만약 실수로 추상메서드를 추가하더라도 컴파일 시점에 오류를 확인할 수 있다.
따라서 함수형 인터페이스를 만들고자 할 때는 @FunctionalInterface 어노테이션을 적극 활용하는 것이 좋다.

 

이렇게 만들어진 함수형 인터페이스는 람다식을 사용하여 구현할 수 있게 된다.

@FunctionalInterface
interface SquareIF {
    int square(int num);
}

public class Test {

    public static void main(String[] args) {
        SquareIF sif1 = (int a) -> {
            return a * a;
        };
        System.out.println(sif1.square(2)); // 4
    }
    
}

 

 

반응형

☕️ 자바에서 제공하는 함수형 인터페이스

함수형 인터페이스를 직접 만들어서 사용할 수도 있지만, 자바에서는 기본적으로 사용할 수 있는 다양한 함수형 인터페이스를 제공하고 있으며 대표적인 인터페이스는 다음과 같다.

  • Consumer
    - T타입 인자 하나를 받으며 리턴값은 없다.

  • Supplier
    - 인자를 받지 않고 T타입을 반환한다.

  • Function
    - T타입 인자를 받아서 R타입을 리턴한다.

  • Predicate
    - T타입의 인자를 받아서 boolean 값을 반환한다.

 

 

 

Consumer 예제 코드
import java.text.DecimalFormat;
import java.util.function.*;

public class ConsumerEx {

    public static void main(String[] args) {
        // 한 개의 파라미터를 소비
        Consumer<String> consumer = s -> System.out.println(s + " World!");
        consumer.accept("Hello"); // Hello World!

        // 두 개의 파라미터를 소비
        BiConsumer<String, String> biConsumer = (t, u) -> System.out.println(t + " " + u);
        biConsumer.accept("Hello", "World!"); // Hello World!

        // double 값을 받아 소비
        DoubleConsumer doubleConsumer = d -> System.out.println("num : " + d);
        doubleConsumer.accept(10); // num : 10.0

        // 객체와 int 값을 받아 소비
        ObjIntConsumer<String> objIntConsumer = (t, u) -> System.out.println(t + u); // 객체, int 파라미터 소비
        objIntConsumer.accept("num : ", 10); // num : 10

        // int 값을 받아 소비(천 단위마다 콤마찍기 기능 추가)
        IntConsumer intConsumer =
                d -> {
                    DecimalFormat decFormat = new DecimalFormat("###,###");
                    System.out.println("num : " + decFormat.format(d));
                };
        intConsumer.accept(10000); // num : 10,000
    }

}

 

 

Supplier 예제 코드
import java.util.Random;
import java.util.function.Supplier;

public class SupplierEx {

    public static void main(String[] args) {
        Supplier<Integer> randomNumbers = () -> new Random().nextInt(10);
        System.out.println(randomNumbers.get()); // 0~9 사이의 랜덤한 값
    }

}

 

 

Function 예제 코드
import java.util.function.Function;

public class FunctionEx {

    public static void main(String[] args) {
        Function<String, String> upperFunction = v -> v.toUpperCase();
        String result = upperFunction.apply("abc");
        System.out.println(result); // ABC

        /* compose()와 andThen()
            * 차이점 : 실행순서의 차이가 있다.
            - compose
                : A.compose(B);
                : B실행 -> A실행

            - andThen
                : A.andThen(B);
                : A실행 -> B실행
         */
        System.out.println(upperFunction.compose(s -> "abc" + s).apply("d")); // ABCD
        System.out.println(upperFunction.andThen(s -> "abc" + s).apply("d")); // abcD
    }

}

 

 

Predicate 예제 코드
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

public class PredicateEx {

    public static void main(String[] args) {
        // 빈 문자인지 비교하여 제거
        List<String> list = Arrays.asList("Java", "C", "", "Python", "", "Kotlin");
        Predicate<String> noneEmptyStringPredicate = s -> !s.isEmpty();
        for (String s : list) {
            boolean result = noneEmptyStringPredicate.test(s);
            if (result) {
                System.out.println(s);
                /* 출력결과
                    Java
                    C
                    Python
                    Kotlin
                 */
            }
        }

        // Stream의 filter()에 인자로 전달
        list.stream().filter(noneEmptyStringPredicate).forEach(System.out::println);
        /* 출력결과
            Java
            C
            Python
            Kotlin
         */



        /*
            AND연산 및 OR연산
            - Predicate의 결과를 AND 연산하거나 OR 연산할 수 있습니다.
         */
        Predicate<Integer> cond1 = (num) -> num > 10;
        Predicate<Integer> cond2 = (num) -> num > 20;
        boolean result;

        // AND연산
        result = cond1.and(cond2).test(15);
        System.out.println(result); // false

        // OR연산
        result = cond1.or(cond2).test(15);
        System.out.println(result); // true



        /*
            isEquals 연산
            - 인자로 전달된 객체와 같은지 확인한다.
         */
        String str1 = new String("abc");
        String str2 = new String("abc");
        Predicate<String> IsEqualPredicate = Predicate.isEqual(str1);
        System.out.println(IsEqualPredicate.test(str2)); // true
    }

}

 

 

 


 

References.

1. 뱀귤 - Java 8 함수형 인터페이스 (Functional Interface)
2. Catsbi's DLog - 함수형 인터페이스와 람다
3. 
DevStory - [Java]함수형 인터페이스(Functional Interface)

 

반응형