본문 바로가기

Reading Record/이펙티브자바

[아이템43~44] 람다 사용법

아이템 43 람다보다는 메서드 참조를 사용하라

람다를 대신하여 메서드 참조라는 기능을 사용하여 더 명확하게 표현할 수 있다.
메서드 참조의 장단점을 알아보자.


장점

메서드 참조는 람다보다 명확하게 표현할 수 있다.

//람다
map.merge(key,1,(count,incr)-> count + incr);

//메서드 참조
map.merge(key,1,Integer::sum);

이 함수는 맵에 키가 있다면 기존매핑 값에 1 증가시키는 코드이다. 메서드 참조를 사용하여 sum이라는 간결한 표현으로 람다를 대체할 수 있었다.


단점

너무 긴 메서드 이름은 오히려 람다가 더 가독성이 뛰어나다.

Function.indentity()메서드는 x->x라는 받은 값을 그대로 반환하는 함수다.

메서드 참조시 x->x가 훨씬 가독성이 뛰어나다.



한정적 참조

다른 메서드 참조는 쉬우니 한정적 참조만 설명하겠다.

    @Test
    @DisplayName("한정적 타입 메서드")
    void name2() {
        //given
        LocalDate targetDate = LocalDate.now();
        Predicate<LocalDate> localDateUnaryOperator = targetDate.minusDays(1)::isAfter;
        assertThat(localDateUnaryOperator.test(targetDate)).isFalse();
    }

한정적 메서드 참조는 인스턴스에 함수의 결과값의 메서드를 참조하는 것이다.



* 주의사항

람다로는 제네릭 함수타입 구현을 표현할 수 없다. 메서드 참조로만 가능하다. 해당 예제는 아래 링크에서 확인하자.

제네릭 함수타입 구현 예제



아이템 44 표준 함수형 인터페이스를 참조하라

이미 자바에는 표준 함수형 인테페이스를 많이 제공하고 있다.

다 알 필요는 없지만, 알아두면 편리한 중요 인터페이스만 알아보자

  1. UnaryOperator
    • 반환값과 인수값이 같은 함수.
    • Unary는 인수값이 하나.
  2. BinaryOperator
    • Unaryoperator와 같고 인수값이 두개이다.
  3. Predicate
    • 인수값 하나를 받아 booleand을 리턴한다.
  4. Function
    • 인수값과 반환타입이 다른 함수
  5. Supplier
    • 인수를 받지 않고 값을 반환한다.
  6. Consumer
    • 들어온 인수값을 소비하고 아무것도 반환하지 않는다.
    @Test
    @DisplayName("표준함수형 인터페이스")
    void name2() {
        //
        UnaryOperator<Integer> unaryOperator = x->x+1;
        assertThat(unaryOperator.apply(1)).isEqualTo(2);
        //
        BinaryOperator<Integer> binaryOperator = (x,y)->x+y;
        assertThat(binaryOperator.apply(1,2)).isEqualTo(3);
        //
        Predicate<Integer> predicate = x-> x==1;
        assertThat(predicate.test(1)).isTrue();
        //
        Function<Integer,String> function = (x) -> String.valueOf(x);
        assertThat(function.apply(1)).isEqualTo("1");
        //
        Supplier<Integer> supplier = ()->1;
        assertThat(supplier.get()).isEqualTo(1);
        //
        Consumer<Integer> consumer = x ->{};   
    }

주의사항

서로 다른 함수형 인터페이스를 같은 위치의 인수로 받는 메서드들을 다중 정의해서는 안된다.

자바에서 다중정의 메서드를 선택하는 방식은 굉장히 복잡하고, 함수형 인터페이스를 받았을때 서로 다른 반환타입을 가진 인터페이스라도
자바에서는 원하는 메서드를 찾지 못해 형변환 해야줘한다.

    @Test
    void name() {
        ExecutorService executorService = Executors.newSingleThreadExecutor();

        //형변환이 없으면 컴파일 에러를 뱉는다.
        executorService.submit((Runnable) System.out::println);

        //람다는 가능
        executorService.submit(() -> 1);
        executorService.submit(() -> {});
    }