[Java] 58. 람다

2025. 7. 4. 23:49·Java/Modern Java(8~)

 

람다

#Java/adv3


람다 정의

  • 자바 8부터 도입된 람다는 자바에서 함수형 프로그래밍을 지원하기 위한 핵심 기능이다.
  • 람다는 익명 함수이다. 따라서 이름 없이 함수를 표현한다.
  • (매개변수) -> {본문}
    • 이름, 반환타입을 적지 않는다.
    • 익명 클래스처럼 new, 클래스명, 메서드 명, 반환 타입 등을 나열할 필요가 없다.
  • 자바는 독립적인 함수를 지원하지 않으며, 메서드는 반드시 클래스나 인터페이스에 속한다

용어 - 람다 vs 람다식(Lambda Expression)

  • 람다: 익명 함수를 지칭하는 일반적인 용어다. 쉽게 이야기해서 개념이다.
  • 람다식: (매개변수) -> {본문} 형태로 람다를 구현하는 구체적인 문법 표현을 지칭한다.

쉽게 이야기해서 람다는 개념을, 람다식은 자바에서 그 개념을 구현하는 구체적인 문법을 의미한다.


람다는 변수처럼 다룰 수 있다

Procedure procedure = () -> { // 람다를 변수에 담음
    System.out.println("hello! lambda");
};

procedure.run(); // 변수를 통해 람다를 실행
  • 람다를 procedure 라는 변수에 담았고, 이 변수를 통해 람다를 실행할 수 있다.

람다도 클래스가 만들어지고, 인스턴스가 생성된다

  • 람다도 익명 클래스처럼 클래스가 만들어지고, 인스턴스가 생성된다.
    • 익명 클래스: $ + 숫자
      • class.class = class lambda.lambda1.InstanceMain$1
    • 람다의 경우 $$로 구분하고 뒤에 복잡한 문자가 붙는다.
      • lambda.class = class lambda.lambda1.InstanceMain$$Lambda/0x00000008000c2618
      • lambda.instance = lambda.lambda1.InstanceMain$$Lambda/0x00000008000c2618@3796751b

정리

  • 람다를 사용하면 익명 클래스 사용의 보일러플레이트 코드를 크게 줄이고, 간결한 코드로 생산성과 가독성을 높일 수 있다.
  • 대부분의 익명 클래스는 람다로 대체할 수 있다.
    • 참고로 람다가 익명 클래스를 완전히 대체할 수 있는 것은 아니다. 람다와 익명 클래스의 차이는 뒤에서 따로 정리하겠다.
  • 람다를 사용할 때 new 키워드를 사용하지 않지만, 람다도 익명 클래스처럼 인스턴스가 생성된다.
  • 지금은 람다를 익명 클래스의 구현을 간단히 표현할 수 있는 문법 설탕(Syntactic sugar, 코드를 간결하게 만드는 문법적 편의) 역할 정도로 생각하자. 람다와 익명 클래스의 차이는 뒤에서 설명한다.

함수형 인터페이스

  • 함수형 인터페이스는 정확히 하나의 추상 메서드를 가지는 인터페이스를 말한다. (인터페이스의 메서드는 모두 추상 메서드!)
  • 람다는 추상 메서드가 하나인 함수형 인터페이스에만 할당할 수 있다.
    • 단일 추상 메서드를 줄여서 SAM(Single Abstract Method)이라 한다.
    • 참고로 람다는 클래스, 추상 클래스에는 할당할 수 없다. 오직 단일 추상 메서드를 가지는 인터페이스에만 할당할 수 있다

SAM이 아닌 경우: 람다 할당 불가

public interface NotSamInterface {
    void run();
    void go();
}

		// 컴파일 오류
        /*
        NotSamInterface notSamInterface = () -> {
            System.out.println("not sam");
        }; 		// 어디로 들어가야 할지 모르기때문에 오류
        notSamInterface.run(); //?
        notSamInterface.go(); //?

  • 람다는 하나의 함수이다. 따라서 람다를 인터페이스에 담으려면 하나의 메서드(함수) 선언만 존재해야 한다.
    • 추상 메서드가 여러 개면, 어디에 담아야 할 지 결정할 수 없다.
    • 자바는 단 하나의 추상 메서드 (SAM: Single Abstract Method)만을 포함하는 함수형 인터페이스에만 람다를 할당할 수 있도록 제한했다.

SAM: 람다 할당 가능

public interface SamInterface {
    void run();
}

  • /@FunctionalInterface
    • @Override를 통해 개발자의 실수를 컴파일 시점에 막을 수 있던 것처럼, 람다에서 또한 단 하나의 추상 메서드를 포함한다는 것을 보장하기 위해 @FunctionalInterface 애노테이션을 붙여준다.
    • 이 애노테이션이 있으면 단 하나의 추상 메서드가 아니면 컴파일 단계에서 오류가 발생한다. 따라서 함수형 인터페이스임을 보장할 수 있다.
    • 람다를 사용할 함수형 인터페이스에는 @FunctionalInterface를 필수로 붙이는 걸 권장한다.(@Override 처럼)
@FunctionalInterface // 애노테이션 추가
public interface SamInterface {
    void run();
}

람다와 시그니처

  • 람다는 결국 함수형 인터페이스의 추상 메서드에 할당하는 거다 메서드의 형태를 정의하는 요소인 메서드 시그니처가 일치해야 한다.
    • 메서드의 시그니처 구성요소
      1. 메서드 이름
      2. 매개변수의 수와 타입(순서 포함)
      3. 반환 타입
  • 람다는 익명 함수이므로 시그니처에서 이름은 제외하고, 매개변수, 반환 타입이 함수형 인터페이스에 선언한 메서드와 맞아야 한다.

람다와 생략

  • 표현식: 하나의 값으로 평가되는 코드 조각. ex) 산술 논리 표현식, 메서드 호출, 객체 생성
  • /단일 표현식1
    • 단일 표현식인 경우 중괄호와 리턴 생략 가능
      • MyFunction function2 = (int a, int b) -> a + b;
    • 단일 표현식이 아닐 경우 중괄호와 리턴 모두 필수
MyFunction function3 = (int a, int b) -> {
	System.out.println("람다 실행");
	return a + b;
};

  • /단일 표현식2:
    • 단일 표현식이고, 매개변수와 반환 값이 없는 경우도 마찬가지로 중괄호 생략 가능하다. (원래 리턴은 생략 가능)
      • Procedure procedure2 = () -> System.out.println("hello! lambda");
    • 타입 추론: 자바 컴파일러는 람다가 사용되는 함수형 인터페이스 메서드 타입을 기반으로 매개변수와 반환값의 타입 추론
      • MyFunction function1 = (int a, int b) -> a + b;
        • 함수형 인터페이스인 MyFunction 의 apply() 메서드를 보면 이미 int a, int b 로 매개변수의 타입이 정의되어 있다.
        • 따라서 이 정보를 사용하면 람다의 (int a, int b) 에서 타입 정보를 생략할 수 있다.
        • 타입 정보 생략: MyFunction function2 = (a, b) -> a + b;
      • 매개변수 타입: 생략 가능하지만 필요하다면 명시적으로 작성할 수 있다.
      • 반환 타입: 문법적으로 명시할 수 없고, 식의 결과를 보고 컴파일러가 항상 추론한다.
    • /매개변수의 괄호 생략
      • 매개변수가 정확히 하나이면서, 타입을 생략하고, 이름만 있는 경우 소괄호 () 를 생략할 수 있다.
        • MyCall call3 = value -> value * 2;
      • 매개변수가 없는 경우에는 () 가 필수이다.
      • 매개변수가 둘 이상이면 () 가 필수이다.

람다의 전달

람다는 함수형 인터페이스를 통해 변수에 대입하거나, 메서드에 전달하거나 반환할 수 있다.

  • /람다를 변수에 대입하기
    • MyFunction add = (a, b) -> a + b;
      • add.apply(1, 2)
    • MyFunction cal = add;
      • cal.apply(1, 2)
    • 변수 add 의 타입은 MyFunction 함수형 인터페이스이다. 따라서 MyFunction 형식에 맞는 람다를 대입할 수 있다. (메서드 시그니처가 일치한다)
    • 람다도 일반 인스턴스 참조값을 대입하는 것과 마찬가지다. 함수형 인터페이스로 선언한 변수에 람다를 대입하는 것은 람다 인스턴스의 참조값을 대입하는 것이다.
      • 람다도 인터페이스(함수형 인터페이스)를 사용하므로, 람다 인스턴스의 참조값을 변수에 전달할 수 있다.
        • 매개변수를 통해 메서드(함수)에 람다를 전달할 수 있다. (정확히는 람다 인스턴스의 참조값을 전달)
        • 메서드가 람다를 반환할 수 있다. (정확히는 람다 인스턴스의 참조값을 반환)
  • /람다를 메서드(함수)에 전달하기
    • MyFunction add = (a, b) -> a + b;
    • static void calculate(MyFunction function) { int result = function.apply(x, y);}
      • 변수를 통해 람다 전달: calculate(add);
      • 람다를 직접 전달: calculate((a, b) -> a + b);
      • 람다를 직접 전달해도 람다 인스턴스가 만들어져 참조값을 전달하는 것은 동일하다.
  • /람다를 반환하기
// 람다를 반환하는 메서드
static MyFunction getOperation(String operator) {
    switch (operator) {
        case "add":
            return (a, b) -> a + b; // 람다 인스턴스를 생성하고 참조값을 반환
        case "sub":
            return (a, b) -> a - b; // 람다 인스턴스를 생성하고 참조값을 반환
        default:
            return (a, b) -> 0; // 람다 인스턴스를 생성하고 참조값을 반환
    }
}

psvm {
	MyFunction add = getOperation("add"); // 람다 인스턴스의 참조값을 대입
    System.out.println("add.apply(1, 2) = " + add.apply(1, 2));

	MyFunction xxx = getOperation("xxx"); // 람다 인스턴스의 참조값을 대입
	System.out.println("xxx.apply(1, 2) = " + xxx.apply(1, 2));
}

고차 함수(Higher Order Function)

  • 람다를 변수에 대입한다는 것은 람다 인스턴스의 참조값을 대입하는 것이고, 람다를 메서드(함수)의 매개변수나 반환값으로 넘긴다는 것 역시 람다 인스턴스의 참조값을 전달, 반환하는 것이다.
    • MyFunction add = (a, b) -> a + b;
    • calculate(add);
    • return (a, b) -> a + b;
  • 고차 함수는 함수를 값처럼 다루는 함수를 뜻한다. 일반적으로 다음 두 가지 중 하나를 만족하면 고차 함수라 한다.
    • 함수를 인자로 받는 함수(메서드)
    • 함수를 반환하는 함수(메서드)
    • "값"을 다루는 것을 넘어, "함수"라는 개념 자체를 값처럼 다룬다는 점에서 추상화의 수준(계층, order)이 한 단계 높아진다고 해서 Higher-Order(더 높은 차원의) 함수라고 부른다.
  • 자바에서 함수를 주고받는다는 것은 "함수형 인터페이스를 구현한 어떤 객체(람다든 익명 클래스든)를 주고받는 것"과 동의어이다. (함수형 인터페이스는 인터페이스이므로 익명 클래스, 람다 둘 다 대입할 수 있다. 하지만 실질적으로 함수형 인터페이스에는 람다를 주로 사용한다.)

Ref) 김영한의 실전 자바 - 고급 3편, 람다, 스트림, 함수형 프로그래밍 강의 | 김영한 - 인프런

'Java > Modern Java(8~)' 카테고리의 다른 글

[Java] 62. 메서드 참조  (0) 2025.07.04
[Java] 61. 람다 vs 익명 클래스  (0) 2025.07.04
[Java] 60. 람다 활용  (0) 2025.07.04
[Java] 59. 함수형 인터페이스  (0) 2025.07.04
[Java] 57. 람다가 필요한 이유  (0) 2025.07.04
'Java/Modern Java(8~)' 카테고리의 다른 글
  • [Java] 61. 람다 vs 익명 클래스
  • [Java] 60. 람다 활용
  • [Java] 59. 함수형 인터페이스
  • [Java] 57. 람다가 필요한 이유
lumana
lumana
배움을 나누는 공간 https://github.com/bebeis
  • lumana
    Brute force Study
    lumana
  • 전체
    오늘
    어제
    • 분류 전체보기 (457)
      • Software Development (27)
        • Performance (0)
        • TroubleShooting (1)
        • Refactoring (0)
        • Test (8)
        • Code Style, Convetion (0)
        • DDD (0)
        • Software Engineering (18)
      • Java (71)
        • Basic (5)
        • Core (21)
        • Collection (7)
        • 멀티스레드&동시성 (13)
        • IO, Network (8)
        • Reflection, Annotation (3)
        • Modern Java(8~) (12)
        • JVM (2)
      • Spring (53)
        • Framework (12)
        • MVC (23)
        • Transaction (3)
        • AOP (11)
        • Boot (0)
        • AI (0)
      • DB Access (1)
        • Jdbc (1)
        • JdbcTemplate (0)
        • JPA (14)
        • Spring Data JPA (0)
        • QueryDSL (0)
      • Computer Science (130)
        • Data Structure (27)
        • OS (14)
        • Database (10)
        • Network (21)
        • 컴퓨터구조 (6)
        • 시스템 프로그래밍 (23)
        • Algorithm (29)
      • HTTP (8)
      • Infra (1)
        • Docker (1)
      • 프로그래밍언어론 (15)
      • Programming Language(Sub) (77)
        • Kotlin (1)
        • Python (25)
        • C++ (51)
        • JavaScript (0)
      • FE (11)
        • HTML (1)
        • CSS (9)
        • React (0)
        • Application (1)
      • Unix_Linux (0)
        • Common (0)
      • PS (13)
        • BOJ (7)
        • Tip (3)
        • 프로그래머스 (0)
        • CodeForce (0)
      • Book Review (4)
        • Clean Code (4)
      • Math (3)
        • Linear Algebra (3)
      • AI (7)
        • DL (0)
        • ML (0)
        • DA (0)
        • Concepts (7)
      • 프리코스 (4)
      • Project Review (6)
      • LegacyPosts (11)
      • 모니터 (0)
      • Diary (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.4
lumana
[Java] 58. 람다
상단으로

티스토리툴바