Study/java

람다 표현식(Lambda Experessions) 정리

유경호 2021. 2. 8. 17:13
반응형

람다 표현식(Lambda Experessions)

함수형 인터페이스의 인스턴스를 만드는 방법으로 쓰일 수 있는 자바8에서 제공하는 강력한 문법 개선 기능입니다. 람다 표현식이 있기 이전에는 하나의 함수만 사용하고 싶어도 클래스를 생성하는 코드를 짰어야 했습니다. 람다 표현식을 사용하면 일급 객체로써 다루어지는 익명 함수를 간단한 코드로 생성할 수 있습니다.

람다식이 평가(evaluation)되면 그 결과 Functional Interface의 인스턴스를 생성합니다. 람다식의 처리 결과는 표현식 몸통을 실행하는 것이 아닙니다. 대신 나중에 이 Functional Interface의 적절한 메서드가 실제 호출(invoke)될 때 표현식 몸통의 실행이 일어게 됩니다.

 

*일급 객체란?

일급 객체(영어: first-class object)란 다른 객체들에 일반적으로 적용 가능한 연산을 모두 지원하는 객체를 가리킨다.

보통 함수에 매개변수로 넘기기, 수정하기, 변수에 대입하기와 같은 연산을 지원할 때 일급 객체라고 한다.


람다식 표현 방법

  • (인자 리스트) -> {바디}

인자 리스트

  • 인자가 없을 때: ()
  • 인자가 한개일 때: (one) 또는 one
  • 인자가 여러개 일 때: (one, two)
  • 인자의 타입은 생략 가능, 컴파일러가 추론(infer)하지만 명시할 수도 있다. (Integer one,Integer two)

바디

  • 화상표 오른쪽에 함수 본문을 정의한다.
  • 여러 줄인 경우에 { }를 사용해서 묶는다.
  • 한 줄인 경우에 생략 가능, return도 생략 가능.

변수 캡처 (Variable Capture)

  • 로컬 변수 캡처
    • final이거나 effective final 인 경우에만 참조할 수 있다.
    • 그렇지 않을 경우 concurrency 문제가 생길 수 있어서 컴파일러가 방지한다.
  • effective final
    • 이것도 역시 자바 8부터 지원하는 기능으로 “사실상" final인 변수.
    • final 키워드 사용하지 않은 변수를 익명 클래스 구현체 또는 람다에서 참조할 수 있다.
      • 단 익명 클래스 구현체, 람다에서 변수를 참조하게 되면 해당 변수는 final로 간주되어 값을 변경할 시 컴파일 시점에 에러를 발생시킨다.
  • 익명 클래스 구현체와 달리 ‘쉐도윙’하지 않는다.
    • 익명 클래스는 새로 스콥을 만들지만, 람다는 람다를 감싸고 있는 스콥과 같다.

표기 예시

() -> {}                // No parameters; result is void
() -> 42                // No parameters, expression body
() -> null              // No parameters, expression body
() -> { return 42; }    // No parameters, block body with return
() -> { System.gc(); }  // No parameters, void block body
 
() -> {                 // Complex block body with returns
  if (true) return 12;
  else {
    int result = 15;
    for (int i = 1; i < 10; i++)
      result *= i;
    return result;
  }
}                         
 
(int x) -> x+1              // Single declared-type parameter
(int x) -> { return x+1; }  // Single declared-type parameter
(x) -> x+1                  // Single inferred-type parameter
x -> x+1                    // Parentheses optional for single inferred-type parameter
 
(String s) -> s.length()      // Single declared-type parameter
(Thread t) -> { t.start(); }  // Single declared-type parameter
s -> s.length()               // Single inferred-type parameter
t -> { t.start(); }           // Single inferred-type parameter
 
(int x, int y) -> x+y  // Multiple declared-type parameters
(x, y) -> x+y          // Multiple inferred-type parameters
(x, int y) -> x+y    // Illegal: can't mix inferred and declared types
(x, final y) -> x+y  // Illegal: no modifiers with inferred types

참고


추가 설명

effective final

자바8 이전에는 내부 변수가 final로 선언되어야 익명 클래스, 익명 객체에서 참조가 되었는데. 이제는 생략할 수 있다.

로컬 클래스, 익명 클래스, 람다 모두 참조 가능

 

람다의 스콥(scope)

이 람다를 감싸고 있는 scope과 동일하여 변수의 쉐도잉이 일어나지 않는다.

예시)

	private void run() {
		int baseNumber = 10;
		
		// 아래와 같이 람다에 baseNumber이란 이름으로 파라미터를 설정하면 컴파일 에러가 난다.
		// run()과 같은 scope이기 때문에 변수가 겹친다.
		IntConsumer printInt = (baseNumber) -> {
			System.out.println(baseNumber  + baseNumber);
		};
		
		printInt.accept(10);
	}
반응형