ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Java 항해일지 - 15. 람다식
    카테고리 없음 2021. 3. 6. 00:19

    목표

    자바의 람다식에 대해 학습하세요.

    학습할 것 (필수)

    • 람다식 사용법
    • 함수형 인터페이스
    • Variable Capture
    • 메소드, 생성자 레퍼런스

    람다란 무엇인가?

    람다 표현식이란 메서드로 전달할 수 있는 익명 함수를 단순화 한 것.

     

    람다의 특징 4가지

    1. 익명: 메서드 이름 없이 사용 가능해 메서드 이름 짓는 것에 대한 고민이 덜어진다.
    2. 함수: 특정 클래스에 종속되지 않는다.
    3. 전달: 람다 표현식 자체를 메서드의 인수로 전달하거나 변수로 저장할 수 있다.
    4. 간결성: 익명클래스보다 간결하다

     

    람다표현식의 구성

    ( 람다 파라미터 ) -> { 람다 바디 }
    • 표현식 스타일
      • (parameters) -> expression
    • 블록 스타일
      • (parameters) -> { statements; }

     

    람다 사용법

    함수형 인터페이스

    함수형 인터페이스는 하나의 추상 메서드만을 정의하는 인터페이스이다. 우테코 로또 미션에서 만들었던 로또 생성 인터페이스를 예시로 들 수 있다.

    public interface LottoGenerator { 
        int MIN_LOTTO_NUMBER = 1; 
        int MAX_LOTTO_NUMBER = 45; 
        int FROM_INDEX = 0; 
        
        Lotto generate(); // 추상 메서드가 오직 하나 
    }

    람다 표현식을 통해 함수형 인터페이스의 추상 메서드 구현을 직접 전달할 수 있어 람다 표현식 자체를 함수형 인터페이스의 인스턴스로 취급할 수 있다. 마찬가지로 로또 미션에서 예시를 가져왔다.

    public static Lotto ofRandomLotto() { 
        // 람다 표현식으로 변경한 예제 
        LottoGenerator randomGenerator = () -> new Lotto(Arrays.asList(1,2,3,4,5,6)); 
        return randomGenerator.generate(); 
    } 
        
    public void makeRandomLottos(int autoAmount) { 
        for (int i = 0; i < autoAmount; i++) { 
            lottos.add(Lotto.ofRandomLotto()); 
        } 
    }

     

    함수 디스크립터

    함수 디스크립터란 람다 표현식의 시그니처를 서술하는 메서드이다. Predicate, Consumer, Function, Supplier 등이 있다.

     

    • Predicate
      제네릭 형식 T의 객체를 인수로 받아 불리언을 반환한다.
    Predicate<String> startsWithSeoul = (str) -> str.startsWith("Seoul"); 
    
    System.out.println(startsWithSeoul.test("SeoulCity")); // true 출력

     

     

    • Consumer
      제네릭 형식 T의 객체를 인수로 받아 void를 반환하는 accept라는 추상 메서드를 정의한다.
    Consumer<String> printCity = (city) -> System.out.println(city); 
    
    printCity.accept("Seoul");

     

     

    • Function
      제네릭 형식 T의 객체를 인수로 받아서 제네릭 형식 R 객체를 반환하는 추상 메서드 apply를 정의한다.
    Function<Integer, Integer> plus10 = (number) -> number + 10; 
    
    System.out.println(plus10.apply(10)); // 20 출력

     

     

    그 외 다양한 함수 디스크립터

    • () -> T : Suuplier
    • T -> T : UnaryOperator
    • (T, T) -> T : BinaryOperator
    • (T, U) -> T : BiPredicate<L, T>
    • (T, U) -> void : BiConsumer<T, U>
    • (T, U) -> R : BiFunction<T, U, R>

     

     

    지역 변수 사용

    람다는 인스턴스 변수와 정적 변수를 자유롭게 캡처할 수 있으나 지역 변수는 명시적으로 final로 선언되어 있어야 하거나, final로 선언된 변수와 똑같이 사용되어야 한다. 다시 말해 한 번만 할당할 수 있는 지역 변수를 캡처(외부에서 정의된 변수를 사용하는 것)할 수 있다.

     

     

    메서드 레퍼런스

    메서드 참조를 이용하면 람다 표현식의 인수를 더 깔끔히 전달할 수 있다.

    1. 정적 메서드 참조 (Integer::parseInt)
    2. 다양한 형식의 인스턴스 메서드 참조 (String::length)
    3. 기존 객체의 인스턴스 메서드 참조 (LottoNumber::getNumber)

     

    생성자 레퍼런스

    ClassName::new와 같이 클래스명과 new 키워드를 이용해 기존 생성자의 참조를 만들 수 있다. 정적 메서드의 참조를 만드는 방법과 비슷하다.

     

     

    람다 표현식을 조합할 수 있는 유용한 메서드

    Comparator 조합

    reversed(), thenComparing() 등을 조합해 사용할 수 있다.

    inventory.sort(comparing(Apple::getWeight)
            .reversed() // 역으로 정렬
            .thenComparing(Apple::getCountry)); 두 사과의 무게가 같으면 국가별 정렬

     

     

    Predicate 조합

    negate(), or(), and() 등을 조합해 사용할 수 있다.

    redApple.and(apple -> apple.getWeight() > 150)
        .or(apple -> GREEN.equals(apple.getColor())); 
    
    // 빨간 사과 중 무게가 150 넘는 사과 혹은 초록 사과 (오른쪽 연결)

     

     

    Function 조합

    andThen(), compose() 등을 조합해 사용할 수 있다.

    Function<Integer, Integer> plus10 = (number) -> number + 10;
    Function<Integer, Integer> multiply3 = (number) -> number * 3;
    
    Function<Integer, Integer> multiply3AndPlus10 = plus10.compose(multiply3); 
    System.out.println(multiply3AndPlus10.apply(4));  // 결과 22
            
            
    Function<Integer, Integer> plus10AndMultiply3 = plus10.andThen(multiply3);
    System.out.println(plus10AndMultiply3.apply(4);  // 결과 42

     

     

     

    정리

    1. 람다 표현식은 익명 함수의 일종이다. 이름만 없을 뿐 파라미터 리스트, 바디, 반환형식을 가지며 예외도 던질 수 있다.
    2. 함수형 인터페이스하나의 추상 메서드만을 정의하는 인터페이스이다.
    3. 람다 표현식 전체가 함수형 인터페이스의 인스턴스로 취급된다.
Designed by Tistory.