람다 표현식은 메서드로 전달할 수 있는 익명 함수를 단순화한 것
람다의 특징
람다의 구성
람다 표현식으로 함수형 인터페이스의 추상 메서드 구현을 직접 전달할 수 있으므로 전체 표현식을 함수형 인터페이스의 인스턴스로 취급 가능
람다 표현식의 시그니처를 서술하는 메서드가 함수 디스크립터
실행 어라운드 패턴: 자원 열고 → 처리 → 자원 닫는 순서로 자원처리하는 패턴
람다를 이용해 동작 전달 가능
함수형 인터페이스 자리에 람다를 사용할 수 있다.
람다 표현식으로 함수형 인터페이스의 추상 메서드 구현을 직접 전달할 수 있으며 전달된 코드는 함수형 인터페이스의 인스턴스로 전달된 코드와 같은 방식으로 처리
람다를 이용해 다양한 동작을 전달 가능
람다 표현식을 사용하려면 공통의 함수 디스크립터를 기술하는 함수형 인터페이스의 집합이 필요
java.util.function에서 새로운 함수형 인터페이스를 제공
test라는 추상 메서드를 정의하며 test는 제네릭 형식 T의 객체를 인수로 받아 불리언을 반환.
T형식의 객체를 사용하는 불리언 표현식이 필요한 상황에서 사용 가능
제네릭 형식 T 객체를 받아서 void를 반환하는 accept라는 추상 메서드를 정의
T 형식의 객체를 인수로 받아서 어떤 동작을 수행하고 싶을 때 사용
제네릭 형식 T를 인수로 받아서 제네릭 형식 R 객체를 반환하는 추상 메서드 apply를 정의
입력을 출력으로 매핑하는 람다를 정의할 때 활용
이러한 변환에는 비용이 소모하는데 자바8에서는 기본형을 입출력으로 사용하는 상황에서 오토박싱을 피할 수 있도록 함수형 인터페이스를 제공
람다가 사용되는 콘텍스트를 이용해서 람다의 형식을 추론 가능
대상 형식이라는 특징 때문에 같은 람다 표현식이더라도 호환되는 추상 메서드를 가진 다른 함수형 인터페이스로 사용될 수 있다.
자바 컴파일러는 사용된 콘텍스트를 이용해서 람다 표현식과 관련된 함수형 인터페이스를 추론
상황에 따라 명시적으로 형식을 포함하는 것이 좋을때도 있고 배제하는 것이 가독성이 좋을 때도 있다. 이는 상황에 맞게 판단
람다 캡처링: 파라미터로 넘겨진 변수가 아닌 외부에서 정의 된 변수를 활용 가능
하지만 지역 변수는 final 선언이 되어 있어야 한다 → 람다 표현식은 한 번만 할당할 수 있는 지역 변수를 캡처할 수 있다.
인스턴스 변수: 힙에 저장
지역 변수: 스택에 저장
변수가 저장된 스레드가 사라진다면 함수가 실행되지 않기 때문에 자바에서는 자유 지역 변수에 복사본을 제공하여 이를 기반으로 함수가 구동→ 복사본의 값이 바뀌지 않아야 하므로 지역변수에는 한 번만 값을 할당해야 한다
메서드 참조를 이용해 기존의 메서드 정의를 재활용해 람다처럼 전달하는 것이 가능
정적 메서드 참조
ex) Integer의 parseInt 메서드는 Integer::parseInte로 표현 가능
다양한 형식의 인스턴스 메서드 참조
ex) String의 length 메서드는 String::length로 표현 가능
기존 객체의 인스턴스 메서드 참조
ex) Transaction 객체를 할당 받은 expenstiveTransaction이라는 지역변수가 있을때 Transaction안에 있는 getvalue 메서드가 있다면 expensiveTransaction::getValue로 표현 가능
::new 키워드를 이용해서 새로운 객체를 생성하고 이를 참조할 수 있다.
함수를 조합하는 것이 가능한데 이를 위해서 나온 것이 디폴트 메서드이다.
thenComparing을 통해서 비교하는 값이 동일할때 그 다음 변수로 정렬하는 함수 조합 가능
inventory.sort(comparing(Apple::getWeight).thenComparing(Apple::getCountry));
negate, and , or 을 통해서 복잡한 predicate을 만들 수 있다.
Predicate<Apple> notRedApple = redApple.negate();
Predicate<Apple> redAndHeavyApple = redApple.and(apple->apple.getWeight() > 150);
Predicate<Apple> redAndHeavyAppleOrGreen = redApple.and(apple->apple.getWeight() > 150).or(apple->GREEN.equals(a.getColor()));
*andThen: 주어진 함수를 먼저 적용한 결과를 다른 함수의 입력으로 전달하는 함수를 반환
Function<Integer, Integer> f = x -> x+1;
Function<Integer, Integer> g = x -> x*1;
Function<Integer, Integer> h = f.andThen(g);
int result = h.apply(1)
// 먼저 1을 더하는 f를 실행 후 g를 실행해 결과 값은 4
Function<Integer, Integer> f = x -> x+1;
Function<Integer, Integer> g = x -> x*1;
Function<Integer, Integer> h = f.compose(g);
int result = h.apply(1)
// 먼저 2를 곱하는 g 실행 후 f를 실행해 결과 값은 3