-
Functional Interface
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); }
이렇게 만들어 볼 수 있겠네요.
'Java' 카테고리의 다른 글
예외처리와 Try With Resources (0) 2024.05.30 가비지 컬렉션 - 가비지 컬렉션의 개념와 작동 방식 (1) 2024.04.13