백기선 자바 스터디 15 람다

Hoyoung Jung·2021년 3월 6일
2

람다식 (Lambda Expression)

  • 자바의 메소드는 일급객체가 아니기 때문에 매개변수나 리턴값으로 사용할 수 없다.
  • 매개변수로 메소드가 필요한 경우 유사한 방식으로 익명클래스를 사용할 수 있지만, 코드가 복잡해진다.
  • 람다 도입 이후로 익명 클래스 대신 람다식을 사용할 수 있게 되었고 코드가 간결해졌다.
  • 람다식 덕분에 고차함수를 간결하게 작성하고 함수형 프로그래밍을 좀 더 가독성있게 할 수 있게 되었다.
  • 람다식을 익명 함수라고 부르지만 실제로는 익명 객체라고 볼 수 있다.
 m.forEach(x->System.out.println(x));

다양한 람다식 표현

//기본형
(int a, int b) -> { return a > b ? a : b; }

//블록 생략
//return 생략
//식이므로 ;도 생략
(int a, int b) -> a > b ? a : b 

//타입 추론이 가능한 경우 타입 생략
(a, b) -> a > b ? a : b

//타입이 없고 매개 변수가 하나일 경우 괄호도 생략 가능
a -> a * a

//single statement의 경우 블록 생략 가능
//return이 포함되어 있으면 중괄호 생략 불가능
(int i) -> System.out.println(i)

FunctionalInterface

  • 람다식을 다루기 위한 인터페이스
  • @FunctionalInterface 어노테이션 사용
  • 어노테이션 자체는 크게 하는일 없어서 RUNTIME 아닐 것 같았는데 Retention이 RUNTIME이었다. (WHY?)
  • 반드시 하나의 추상 메서드만 정의되어 있어야 한다.

FunctionalInterface 예제

@FunctionalInterface
interface MyFunc {
    void foo();
}

void bar(MyFunc f) {
    f.foo();
}

bar(() -> System.out.println("Hello"));

미리 정의해 놓은 Functional Inteferface

인터페이스메소드매개변수리턴 값
Runnablevoid run()0void
SupplierT get()0T
Consumervoid accept(T t)1void
Function<T, R>R apply(T t)1R
Predicateboolean test(T t)1boolean
BiFunction<T, U, R>R apply(T t, U u)2R
import java.util.Arrays;
import java.util.List;
import java.util.function.Supplier;

class MyList {
    private List<Integer> numbers = Arrays.asList(1, 2, 3);

    public void forEach(Supplier<Integer> s) {
        for (int x : numbers) {
            System.out.println(s.get());
        }
    }

    public static void main(String[] args) {
        MyList m = new MyList();
        m.forEach(()-> 5);
    }
}

컬렉션과 람다

Java 1.8부터 컬렉션 프레임워크에도 함수형 인터페이스를 사용하는 메소드들이 추가되었다.
유용하게 사용되니 배워보자.


<출처: 자바의 정석 기초편 564p>

스트림

  • 특정한 타입의 원소들의 시퀀스(sequence), 순차 혹은 병렬로 처리 가능하다.
  • Collection을 stream으로 변환해서 처리할 수 있다.
  • 한 스트림으로 두 번 처리는 되지 않는다.
  • 중간연산과 최종연산으로 구분되며 최종연산을 수행하기 전까지 중간연산은 수행되지 않는다.
int sum = widgets.stream()
                      .filter(w -> w.getColor() == RED) //중간연산
                      .mapToInt(w -> w.getWeight()) //중간연산
                      .sum(); //최종연산

Variable Capture

  • 다른 언어의 closure와 같은 것
  • 람다식을 사용할 때 외부변수를 람다식 내부에서 접근할 수 있다.
  • 접근 가능 대상: 지역 변수, 인스턴스 변수, 스태틱 변수
  • 주의: 지역변수는 final (effectively final) 변수여야 한다.
int i = 5;
Supplier<String> x = () -> {
    i = i * i; //error
    return "hello " + i;
};

메소드 참조

  • 람다식의 축약형 표현
  • 람다 표현식에서 단 하나의 메소드만을 호출하는 경우 사용 가능
(x) -> System.out.println(x)
System.out::println

생성자 참조

  • 마찬가지로 생성자도 축약해서 표현할 수 있다.
  • 아, 그렇구나.
() -> { return new Player() }
() -> Player:: new
profile
주짓수를 좋아하는 개발자

0개의 댓글