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
참고
- https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html#shadowing
- https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html
추가 설명
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);
}
반응형