ABOUT ME

Today
Yesterday
Total
  • 함수형 인터페이스
    Java 2024. 4. 18. 17:35

    Functional Interface

    https://download.java.net/java/early_access/panama/docs/api/java.base/java/util/function/package-summary.html

    Since 1.8

    Functional Interface 는 람다 표현식과 메소드 레퍼런스에 대한 타겟 타입을 제공합니다.

     

    각각의 Functional Interface는 Functional method라고 불리는 단일 추상 메소드를 가지고 있습니다.

     

    @Functional Interface 어노테이션:

    해당 인터페이스가 함수형 인터페이스로 될 수 있는지 컴파일단계에서 검증하기 위한 어노테이션

     

    함수형 인터페이스는 하나의 추상 메소드만 요구하지만,

    여러 개의 디폴트 또는 정적 메소드를 포함할 수 있습니다.

     

    Functional Interface는 복수의 컨텍스트에 타겟타입을 제공합니다.

    // Assignment context
    Predicate<String> p = String::isEmpty;
    
    // Method invocation context
    stream.filter(e -> e.getSize() > 10)
    
    // Case context
    stream.map((ToIntFunction) e -> e.getSize())

     

    Functional Interface 는 확장가능한 네임 컨벤션을 따릅니다.

     

    근데 문득 Assignment context 예시에서 이상한 ( :: ) 이 보이네요

    이는 메소드 참조라고 불립니다.

    메소드 참조

    함수형 인터페이스의 구현을 기존의 메소드 호출로 직접 매핑함으로서 람다표현식을 간단하게 표현할 수 있게 도와줍니다.

     

    여기서 “함수형 인터페이스의 구현을 기존의 메소드 호출로 직접 매핑함”이 가지는 의미는

     

    함수형 인터페이스 내에 있는 하나의 추상 메소드를 이미 존재하는 메소드와 직접 연결한다는것

    함수형 인터페이스에 있는 추상 메소드를 특정 메소드의 구현으로서 바로 사용하는 것

     

    메소드 참조의 경우에는

    정적 메소드 참조, 특정 객체의 인스턴스 메소드 참조, 임의 객체의 인스턴스 메소드 참조, 클래스 생성자 참조를 제공합니다.

    // 정적 메소드 참조
    BinaryOperator<Integer> maxFunction = Math::max; 
    // Math 클래스의 정적 메소드인 max 참조
    maxFunction.apply(5, 10);
    
    // 특정 객체의 인스턴스 메소드 참조 
    Consumer<String> printer = System.out::println;
    // System클래스의 인스턴스 변수인 out에 해당하는 메소드 println 참조
    printer.accept("hello world");
    
    // 임의의 객체의 인스턴스 메소드 참조
    Function<String, Integer> lengthFunction = String::length;
    // String클래스의 객체에 해당하는 인스턴스 메소드 length 참조
    lengthFunction = String::length;
    
    // 클래스의 기본생성자 참조
    Supplier<List<String>> listSupplier = ArrayList::new
    // ArrayList의 기본생성자를 참조합니다.
    // 이 때 Supplier<T> 에서 T타입으로 ArrayList클래스 객체가 하나 생성됩니다.
    List<String> list = listSupplier.get();

     

    예를 들어서

     

    Function<T, R> 는 하나의 추상 메소드인 R apply(T t)를 가집니다.

     

    Function 인터페이스를 직접 열어본 모습

     

    여기서 Integer 값을 받아서 String으로 변환하는 함수를 Function을 사용해서 구현하면

    Function<Integer, String> function = num -> Integer.toString(num);

    이됩니다.

     

    여기서 Integer클래스의 toString은 static 메소드이기 때문에 메소드 참조형이 가능합니다.

    Function<Integer, String> function = Integer::toString;

     

    자바에서 함수형 인터페이스의 예시

     

    Runnable : 어떤 인자도 받지 않고, 반환값도 없는 작업을 실행하기 위한 인터페이스

    Runnable runnable = () -> System.out.println("Hello, World");
    runnable.run();

     

    Supplier <T>: 어떤 인자도 받지않고 반환값은 있는 작업을 실행하기 위한 인터페이스

    Supplier<Double> randomValue = () -> Math.random();
    Double value = randomValue.get();

     

    Consumer<T> : 하나의 인자를 받고, 반환값은 없는 작업을 실행하기 위한 인터페이스

    Consumer<String> printer = System.out::println;
    printer.accept("Hello, Consumer!");
    

     

    Function<T, R> : T타입의 인자를 받아서 R타입의 결과를 반환하는 작업을 실행하기 위한 인터페이스

    Function<Integer, String> converter = Object::toString;
    String text = converter.apply(123);
    

     

    만약 2개 이상의 인자를 받는 함수형 인터페이스를 만들고 싶다면?

     

    자바 표준 라이브러리에는 2개의 인자를 받아서 처리하는 함수형 인터페이스가 존재합니다.

    바로 BiFunction<T, U, R> 입니다.

     

    BiFunction<T, U, R> 로서 R apply(T t, U u)라는 추상메서드가 존재하고

    T 타입의 인자와 R타입의 인자를 받아서 R타입을 반환합니다.

     

    사용예시로는

    BiFunction<Integer, Integer, String> sumToString = (a, b) -> String.valueOf(a+b);
    String result = sumToString.apply(10, 20);
    

     

    만약 2개보다 더 많은 인자를 받고 싶다면

    직접 interface를 만들어야 합니다.

    만약 3개의 인자를 받는 함수형 인터페이스를 만든다면

    @FunctionalInterface
    public interface TriFunction(T, U, V, R){
    	R apply(T t, U u, V v);
    }
    

     

    이렇게 만들어 볼 수 있겠네요.

Designed by Tistory.