람다 표현식이란?
자바 8에 추가된 함수형 프로그래밍 요소
객체지향이 객체의 필드에 데이터를 저장하고 그를 다루는데에 반해,
함수형 프로그래밍은 선언적이어서 statement보다 선언, 혹은 표현식을 사용한다.
자바8의 람다식은 다음과 같은 형태를 가진다
parameters -> expression body
ex ) Comparator comparator = (a, b) -> a.compareTo(b)
람다 표현식의 특징
타입 선언이 선택적이다 .
싱글 파라미터의 경우 괄호가 필요 없다.
중괄호 선택 : 한문장일 경우 중괄호가 필요 없다
return 키워드 선택 : 한문장일 경우 생략 가능하다, 다만 중괄호를 포함한 경우 무조건 return 포함해야한다.
람다식을 이용하려면 오버라이드 할 메서드가 포함된 함수형 인터페이스가 필요하다.
함수형 인터페이스는 함수를 하나만 가지는 인터페이스에, 함수형 인터페이스 어노테이션(@FunctionalInterface)를 붙여 명시한다.
자바 API에 내장된 대표적인 함수형 인터페이스로는 Runable이나 Comparator가 있다.
Java 8 이전 방식과 람다 표현식
1. 클래스 생성
public class MyRunnable implements Runnable { @Override public void run() { System.out.println("I have implemented Runnable"); } public static void main(String args[]) { MyRunnable runnable = new MyRunnable(); runnable.run(); } }2. 익명 클래스
Runnable runnable = new Runnable() { @Override public void run() { System.out.println("I have implemented Runnable"); } }; runnable.run();
3. 람다식 사용
Runnable runnable = () -> System.out.println("I have implemented Runnable"); runnable.run();
함수형 인터페이스
람다를 사용하기 위해선 추상메서드를 하나만 가지는 함수형 인터페이스가 필요하다.
함수형 메서드의 추상 메서드 시그너처를 함수 디스크립터라고 한다.
자바8에는 java.util.function에 Predicate, Consumer, Function 등, 그 외 여러 인터페이스가 이미 구현되어있다.
대표적인 함수형 인터페이스
함수형 인터페이스 |
함수 디스크립터 |
Predicate<T> |
T->boolean |
Consumer<T> |
T->void |
Function<T, R> |
T->R |
Supplier<T> |
()->T |
UnaryOperator<T> |
T->T |
BinaryOperator<T> |
(T, T)->T |
BiPredicate<L, R> |
(L, R)->boolean |
BiConsumer<L, R> |
(L, R)->void |
BiFunction<T, U, R> |
(T, U,)->R |
autoboxing에 대한 리소스를 줄이기 위해 각 함수형 인터페이스엔 기본형 특화 인터페이스가 존재하며, 인터페이스 네임 서두에 자료형을 붙인 형태이다.
Function같은 경우 파라미터와 반환형을 명시하기 위해 ToIntFunction, DoubleToIntFunction등이 존재한다.
형식 검사
컴파일러는 람다가 사용되는 컨텍스트를 기반으로 람다의 형식을 추론한다.
어떤 컨텍스트에서 기대되는 람다 표현식의 형식을 대상 형식이라고 부른다.
형식을 검사하는 순서는 다음과 같다.
람다 선언부 확인(람다가 매서드 파라미터로 사용시 매서드 선언부 확인)
선언부에서 대상형식 확인.
대상형식이 함수형 인터페이스인지 확인.
대상형식의 추상 메서드 확인.
추상메서드의 함수 디스크립터와 람다의 시그니처를 비교하여 형식 검사를 완료한다.
형식 추론
자바 컴파일러는 콘텍스트를 통해 람다 표현식과 관련된 함수형 인터페이스를 추론한다..
즉 형식 검사를 통해 함수 디스크립터를 알 수 있으므로, 컴파일러는 람다의 시그니처 또한 추론 할 수 있다.
람다의 시그니쳐 추론을 통해 람다 표현식의 파라미터 형식에 접근 할 수 있으므로 파라미터의 형식이 생략 가능하다.
(앞서 정리한 특징 중 '1. 타입 선언이 선택적이다'에 해당한다.)
람다 표현식의 유효 범위
람다표현식은 java에서 정의된 명명규칙인 name conflicts와 shadowing 규칙이 똑같이 적용된다.
즉 람다 파라미터나 람다 표현식 내에 람다가 선언되는 지역의 지역변수와 똑같은 이름의 변수를 선언 할 수 없다.
this키워드 또한 람다표현식 내에서 사용할 경우, 람다 표현식이 선언되는 메서드의 this 파라미터를 의미한다.
외부 유효범위의 변수 접근
람다 표현식 외부에 있는 변수를 람다가 사용할 경우, 해당 변수를 자유 변수라 부른다.
람다가 자유변수를 capture하기 위해서
자유 변수는 final이거나 변하지 않는 effectivley final 변수여야 한다.
참조 : https://dzone.com/articles/a-little-lambda-tutorial, 카이호스트만 코어 자바 8