자바 언어·플랫폼 용어 사전
함수형함수형 인터페이스 · 메서드 참조 · invokedynamic

람다

함수를 값처럼 다루는 문법. 익명 클래스와 달리 invokedynamic으로 실행 시점에 구현이 만들어진다.

함수를 값처럼 넘기는 문법. 추상 메서드가 하나뿐인 인터페이스(함수형 인터페이스) 자리에 쓸 수 있다.

list.sort((a, b) -> a.age() - b.age());
list.forEach(System.out::println);           // 메서드 참조

익명 클래스와 무엇이 다른가

  • 익명 클래스 — 컴파일 시점에 별도 클래스 파일이 생긴다 (Outer$1.class)

    • this 가 익명 클래스 자신을 가리킨다
    • 클래스 로딩 비용이 개수만큼 든다
  • 람다 — 클래스 파일이 안 생긴다

    • invokedynamic 명령 + LambdaMetafactory 가
    • '첫 호출 시점' 에 구현 객체를 만들어 준다
    • this 가 바깥 인스턴스를 가리킨다
class A {
    Runnable r1 = new Runnable() { public void run() { System.out.println(this); } };  // 익명 클래스
    Runnable r2 = () -> System.out.println(this);                                       // A 인스턴스
}

상태가 없으면 인스턴스를 재사용한다

Runnable r = () -> System.out.println("hi");   // 캡처하는 값이 없다 → 싱글턴처럼 재사용
Runnable s = () -> System.out.println(x);       // x 를 캡처한다 → 호출마다 새 객체

캡처가 없으면 객체 생성 비용도 거의 없다 — 그래서 스트림 연산에 람다를 남발해도 대체로 괜찮다.

사실상 final만 캡처할 수 있다

int count = 0;
list.forEach(x -> count++);     // 컴파일 에러: effectively final 이어야 한다

// 우회
int[] count = {0};
list.forEach(x -> count[0]++);  // 동작하지만 병렬에서는 안전하지 않다
long n = list.stream().filter(...).count();   // ✅ 이런 건 스트림으로 표현한다

지역 변수는 스택에 있고 람다는 그보다 오래 살 수 있어서 값을 복사해 갖는다. 그래서 원본을 바꿀 수 없다.

주요 함수형 인터페이스

Function<T,R>    T 를 받아 R 을 반환     apply
Predicate<T>     T 를 받아 boolean       test
Consumer<T>      T 를 받고 반환 없음     accept
Supplier<T>      받지 않고 T 를 반환     get
UnaryOperator<T> T → T
  • 원시 타입 특화도 있다 — IntPredicate · ToIntFunction (박싱을 피한다)

메서드 참조 네 가지

String::valueOf          // 정적 메서드
system::println          // 특정 인스턴스의 메서드
String::length           // 임의 객체의 인스턴스 메서드 (첫 인자가 수신자가 된다)
Member::new              // 생성자

예외가 걸림돌이 된다

list.forEach(f -> Files.readString(f));   // 컴파일 에러 — Consumer 는 검사 예외를 못 던진다

// 감싸는 유틸을 만들거나, 애초에 검사 예외를 피하는 API 를 쓴다
list.forEach(f -> { try { Files.readString(f); } catch (IOException e) { throw new UncheckedIOException(e); } });

면접 함정

  • "람다는 익명 클래스의 문법 설탕" → 컴파일 결과가 다르다(invokedynamic).
  • "람다 안에서 지역 변수를 바꿀 수 있다" → effectively final만 캡처된다.

함께 보면 좋은 용어

노트에서 맥락과 함께 보기 — 함수형 프로그래밍·Stream