2022 10 18
2022-10-18¶
함수형 인터페이스¶
- 정의 : 하나의 메서드가 선언된 인터페이스를 정의하여 람다식을 다루는 기술
- 느낀점
- 하나의 메서드를 가진 인터페이스를 정의하고,
- 해당 메서드를 람다식으로 구체화 시켜 하나의 클래스로 구현하면,
- 실질적으로는 이걸 결국 한번 호출해주는 로직이 필요함.
- 마치 객체 Call 하듯
- 써보기
Test test = () -> System.out.println("Test!"); // 내가 만든거 test.print(); //메서드 하나는 호출해줘야하네? // String을 반환받는 함수형 인터페이스 Supplier<String> supplierTest = new Supplier<String>() { @Override public String get() { return "Hello!"; } }; String supplier = supplierTest.get(); System.out.println("supplier = " + supplier); // String을 제공하는 함수형 인터페이스 Consumer<String> consumerTest = new Consumer<String>() { @Override public void accept(String s) { System.out.println("s = " + s); } }; consumerTest.accept("hello~"); // String을 받아 Integer를 반환하는 인터페이스 Function<String, Integer> functionTest = new Function<String, Integer>() { @Override public Integer apply(String s) { return s.length(); } }; Integer value = functionTest.apply("hello world"); System.out.println("value = " + value); // String, String을 받아 String을 반환하는 인터페이스 BiFunction<String, String, String> biFunctionTest = (a, b) -> (a + b); String apply = biFunctionTest.apply("hello", "world"); System.out.println("apply = " + apply); // String을 받아 Boolean을 반환하는 인터페이스 Predicate<String> predicateTest = s -> s.equals("hello"); boolean hello = predicateTest.test("hello"); System.out.println("hello = " + hello); boolean world = predicateTest.test("world"); System.out.println("world = " + world); // 다음과 같이 체이닝도 가능함 Function<String, String> rightWay = s -> s; Function<String, String> reverseWay = s -> { StringBuilder stringBuilder = new StringBuilder(s); stringBuilder.reverse(); return stringBuilder.toString(); }; Function<String, String> rightAgain = rightWay.andThen(reverseWay).andThen(reverseWay); String result = rightAgain.apply("test"); System.out.println("result = " + result);
- 메서드 참조를 활용하여 람다식을 간단히 표현 가능 (from Java8)
-
Connectable에서는?
- DTO 변환해주는 로직. 메서드 참조를 통해 구현함.
- 그냥 TicketMetadataAttribute를 받아 TicketMetadataAttributeResponse로 변환해주는 함수형 인터페이스를 매개변수로 받음.
public static TicketMetadataAttributeResponse of(TicketMetadataAttribute attribute) { return new TicketMetadataAttributeResponse( attribute.getTrait_type(), attribute.getValue() ); } public static List<TicketMetadataAttributeResponse> toList(List<TicketMetadataAttribute> attributes) { return attributes.stream() .map(TicketMetadataAttributeResponse::of) .collect(Collectors.toList()); }
- 독특하게도 map은 다음과 같이 구현되어있음
- 왜 input은 super지?
- 해당 input은 본인과 부모 클래스만 인풋으로 받을 수 있다는 것인데...
- input을 부모로 받는 함수더라도, 자식을 부모가 품을 수 있기때문에 딱히 문제는 없겠구나
- function이 실행되는 시점에 input의 부모로 치환하여 함수를 실행할 수 있음
- 왜 output은 extends지?
- 해당 output은 본인과 자식들만 구현할 수 있다.
- 반환하는 값이 결국 본인으로 매핑되니까, 함수를 수행하는 결과값이 자식이더라도 부모로 변경할 수 있어 괜찮은가보다
- 부모가 자식을 품을 수 있으니, 반환값은 자식이더라도 부모로 싹 변환하여 처리가능
- 왜 input은 super지?
- 요런 괴랄한 로직도 가능
public static void main(String[] args) { // 와일드카드를 활용하여 List<? extends GrandParent> 만들기 List<? extends GrandParent> family = List.of(new GrandParent(), new Parent(), new Child()); // input은 Object 타입, output은 ? extends Parent Function<Object, ? extends Parent> toChild = new Function<Object, Parent>() { @Override public Parent apply(Object child) { // Child 타입이면 Parent 반환 if (child instanceof Child) { return new Parent(); } else { return new Child(); } } }; List<? extends Parent> collect = family.stream() .map(toChild) // 여기서 map은... // input : ? super (capture of ? extends GrandParent) -> Object도 가능하겠다 // output : ? extends Parent .collect(Collectors.toList()); System.out.println("collect = " + collect); } // collect = [playground.generic.family.Child@52d455b8, playground.generic.family.Child@4f4a7090, playground.generic.family.Parent@18ef96]
- 2트
public static void main(String[] args) { List<? extends GrandParent> family = List.of(new GrandParent(), new Parent(), new Child()); Function<Object, Parent> toChild = new Function<Object, Parent>() { @Override public Parent apply(Object child) { if (child instanceof Child) { return new Parent(); } else { return new Child(); } } }; List<Parent> collect = family.stream() .map(toChild) .collect(Collectors.toList()); System.out.println("collect = " + collect); } // collect = [playground.generic.family.Child@52d455b8, playground.generic.family.Child@4f4a7090, playground.generic.family.Parent@18ef96]