함수형 인터페이스(Functional Interface)
- 단 하나의 추상 메서드만을 가진다.
- 함수를 값으로 취급하기 때문에 어떤 함수를 호출할 때, 함수 자체를 파라미터로 전달가능하다.
단 하나의 추상 메서드를 가지는 인터페이스 예제
public class Example {
public static void main(String[] args) {
List<CryptoCurrency> cryptoCurrencies = SampleData.cryptoCurrencies;
Collections.sort(cryptoCurrencies, new Comparator<CryptoCurrency> () {
@Override
public int compare(CryptoCurency c1, CryptoCurrency cc2) {
return cc1.getUnit().name().compareTo(cc2.getUnit().name());
}
});
- crypthCurrencies 객체를 화폐단위의 오름차순으로 정렬하기 위해 추가적으로 Comparator 인터페이스를 사용
- Comparator 인터페이스를 익명 구현 객체의 형태로 Collections.sort() 파라미터로 전달하는데, 길어지고 지저분함.
- 인터페이스의 익명 구현 객체를 전달하는 방식을 함수형 프로그래밍 방식에 맞게 표현한 것을 람다 표현식
람다 표현식은 함수를 값으로 취급하기 위해 표현된 간결한 형태의 표현식이다.
- 즉 함수형 인터페이스를 구현한 클래스의 메서드 구현을 단순화한 표현식입니다.
(String a, String b) -> e.equals(b)
- 람다 파라미터, 람다 몸체로 구성
public class Example {
public static void main(String[] args) {
List<CryptoCurrency> cryptoCurrencies = SampleData.cryptoCurrencies;
Collections.sort(cryptoCurrencies,
(cc1, cc2) -> cc1.getUnit().name().compareTo(cc2.getUnit().name()));
});
- 함수형 인터페이스를 구현한 클래스의 인스턴스를 람다 표현식으로 작성해서 전달한다.
- 람다 표현식 외부에서 정의된 자유변수를 람다 표현식에 사용하는 것을 람다 캡처링이라 한다. (Lambda Capturing)
- String korBTC = "비트코인"; korBTC = "비트코인2"; cryptoCurrecies.stream() .filter(cc-> cc.getUnit() == CurrenccyUnit.BTC) .map(cc -> cc.getName() + '(' + korBTC + ")" ) .forEach(System.out::println));
메서드 레퍼런스
Car::getCarName
- 람다 표현식 몸체에 기술된 getCarName()을 메서드 레퍼런스로 표현함
- ClassName:: static Method 유형
- String korBTC = "비트코인"; korBTC = "비트코인2"; cryptoCurrecies.stream() .map(cc -> cc.getName()) .map(StringUtills::upperCase) .forEach(name -> System.out.println(name));
- ClassName:: instance Method 유형
- String korBTC = "비트코인"; korBTC = "비트코인2"; cryptoCurrecies.stream() .map(cc -> cc.getName()) .map(String::upperCase) .forEach(name -> System.out.println(name));
- object :: Instance method 유형
- PaymentCalculator calculator = new PaymentCalculator(); cryptoCurrecies.stream() .filter(cc-> cc.getUnit() == CurrenccyUnit.BTC) .map(cc > new ImmutablePair(cc.getPrice(), amount)) .map(pair -> calculator.getTotalPayment(pair)) .map(calcultor::getTotalPayment) .forEach(System.out::println);
- ClassName :: new 유형
- Optional<PaymentCalcultor> optioanl = cryptoCurrencies.stream() .filter(cc -> cc.getUnit() == CurrencyUnit.BTC) .map(cc -> new ImmutablePair(cc.getPrice(), amount)) .map(PaymentCalcultor::new) .findFirst();
함수 디스크립터
함수 디스크립터는 함수 서술자, 함수 설명자 정도로 이해 가능한데, 일반화된 람다 표현식을 통해서 이 함수형 인터페이스가 어떤 파라미터를 가지고, 어떤 값을 리턴하는지 설명하는 역할을 한다.
- Predicate
- T → boolean
public class Examle { public static void main(String[] agrgs) { List<CryptoCurrency> result = filter(cryptoCurrencies, cc -> cc.getPrice() > 500000);
private static List<CryptoCurrency> filter(List<CryptoCurrency> CryptoCurrencies, Predicate<CryptoCurrency> p) { List<CryptoCurrecy> result = new ArrayList<>(); for (CryptoCurrency cc : cryptoCurrencies) { if (p.test(cc)){ result.add(cc); } return result; } }
- @FunctionalInterface public interface Predicate<T> { boolean test(T t); }
- Consumer 함수형 인터페이스
- T → void
- 일정 주기별로 특정 작업을 수행한 후, 결과 값을 리턴할 필요가 없는 경우가 대부분인 배치처리
@FunctionalInterface public interface Consumer<T> { void accept(T t); }
- Function 함수형 인터페이스
- T → R
- Java 스트림의 Map 메서드
@FuncitonalInterface public interface Funciton<T, R> { R apply (T t); }
- Supplier
- @FuncitonalInterface public interface Supplier<T> { T get(); }
- Bixxxxx
- 추상 메서드에 전달하는 파라미터가 하니나 더 추가되어 두 개의 파라미터를 가짐.
- T → boolean
'📗 BOOK > 스프링으로 시작하는 리액티브 프로그래밍' 카테고리의 다른 글
3장 Blocking I/O vs Non-Blocking I/O (0) | 2024.11.20 |
---|---|
2장 리액티브 스트림즈 (1) | 2024.11.20 |
1장 리액티브 시스템과 리액티브 프로그래밍 (0) | 2024.11.20 |