함수적 프로그래밍은 병렬 처리와 이벤트 지향 프로그래밍에 적합하다. 그래서 객체 지향 프로그래밍과 함수적 프로그래밍을 혼합하여 효율적인 프로그래밍이 될 수 있도록 개발 언어가 변하고 있다.
람다식은 익명 함수를 생성하기 위한 식으로 객체 지향 언어보단 함수 지향 언어에 가깝다. 이를 통해 자바 코드가 매우 간결해지고 컬렉션 요소를 필터해 원하는 결과를 쉽게 집계할 수 있다.
람다식 → 매개 변수를 가진 코드 블록 → 익명 구현 객체
(타입 매개변수, ...) → { 실행문; ... }
인터페이스가 직접 객체화 할 수 없으므로 구현 클래스로 람다식을 사용한다. 람다식은 익명 구현 클래스를 생성하고 객체화한다. 이때 람다식이 대입될 인터페이스를 타겟 타입이라고 한다.
두 개 이상의 추상 메소드가 선언된 인터페이스는 타겟 타입이 될 수 없고 하나의 추상 메소드가 선언된 인터페이스만 타겟 타입이 될 수 있다. 이러한 인터페이스를 함수적 인터페이스 라고 부른다.
@FunctionalInterface 어노테이션을 붙이면 두 개이상의 추상 메소드가 선언되지 않도록 컴파일러가 체킹해주고 두 개이상 선언되면 컴파일 오류를 발생시킨다.
람다식에서 this는 내부적으로 생성되는 익명 객체의 참조가 아닌 람다식을 실행한 객체의 참조다. (js 랑 비슷..js 가 java 따라한건가..?)
자바에서 제공되는 표준 API 인터페이스 들 중 한 개의 추상 메소드를 갖는 것들은 람다식을 이용해서 익명 구현 객체로 표현이 가능하다.
리턴값이 없는 accept() 메소드를 가지고 있다. accept() 메소드는 단지 매개값을 소비(사용만 할뿐 리턴값은 없음)만 한다.
매개 변수가 없고 리턴값이 있는 getXXX() 메소드를 가진다.
매개값과 리턴값이 있는 applyXXX() 메소드를 가진다.
Operator 함수적 인터페이스는 Function과 동일하다. 즉 매개 변수와 리턴값이 있는 applyXXX() 메소드를 가진다. 하지만 Function과 다르게 매개값을 리턴값으로 매핑(타입 변환)하는 역할보단 매개값으로 연산을 수행 후 동일한 타입으로 리턴값을 제공한다.
매개 변수와 boolean 리턴값이 있는 testXXX() 메소드를 가진다. 매개값을 조사해 true 또는 false 를 리턴한다.
디폴트 및 정적 메소드는 추상 메소드가 아니다. 그러므로 함수적 인터페이스에 선언되어도 여전히 함수적 인터페이스 성질을 잃지 않는다. 여기서 함수적 인터페이스 성질이란 하나의 추상 메소드를 가지고 있고, 람다식으로 익명 구현 객체를 생성할 수 있는 것을 말한다.
인터페이스AB = 인터페이스A.andThen(인터페이스B)
최종결과 = 인터페이스AB.method();
인터페이스AB = 인터페이스A.andThen(인터페이스B)
최종결과 = 인터페이스AB.method();
메소드 참조는 메소드를 참조해서 매개 변수의 정보 및 리턴 타입을 알아내 람다식에서 불필요한 매개 변수를 제거하는 것이 목적이다.
예를 들면 람다식에선 메소드 호출을 주로 하는 경우가 많다.
(left, right) -> Math.max(left, right);
// 람다식은 여기서 단순히 매개변수를 전달하는 역할만 한다.
// 이는 다소 소모적인데 이를 다음과 같이 메소드 참조를 이용해서 바꿀 수 있다
Math :: max;
// 정적 메소드 참조시
클래스 :: 메소드
// 인스턴스 메소드 참조시
참조변수 :: 메소드
메소드는 람다식 외부 클래스 멤버일 수도 있고 람다식에서 제공되는 매개 변수의 멤버일 수도 있다. 만약 후자인 경우 해당 매개 변수 타입의 클래스 이름과 메소드를 아래와 같이 나열하면 된다.
클래스 :: instanceMethod
생성자 참조가 가능하다는 것은 객체 생성이 된다는 것이다. 생성자 참조는 다음과 같이 표현할 수 있다.
클래스 :: new
여러 개의 생성자가 오버로딩 되어 있는 경우, 컴파일러는 함수적 인터페이스의 추상 메소드와 동일한 매개 변수 타입과 개수를 가지고 있는 생성자를 찾아내어 실행한다.