- 메소드(함수)를 간단한 식으로 표현하는 방법
- 익명 객체 (반환 타입과 이름이 없음)
- 함수는 클래스에 독립적이고 메소드는 클래스에 종속적
람다식 작성
// 기존 메소드 정의
int max(int a, int b) {
return a > b? a : b;
}
// 람다식 적용
// 1. 메소드의 이름과 반환타입을 제거하고 {메소드블록} 전에 -> 를 추가
(int a, int b) -> {
return a > b? a : b;
}
// 2. 반환값이 있는 경우에는 식이나 값만 적고 return문 생략 가능하며 끝에 ;도 생략
(int a, int b) -> a > b? a : b
// 3. 매개변수의 타입도 예상 가능한 경우 생략 가능 (대부분 생략 가능)
(a, b) -> a > b? a : b
작성시 주의사항
// 매개변수가 하나이고 타입이 없는 경우 경우 괄호 생략가능
(a) -> a * a // a -> a * a 처럼 괄호 생략 가능하지만
(int a) -> a * a // int a -> a * a 는 타입이 있기 때문에 생략 불가능
// 블록 안의 문장이 하나만 있는 경우 {}, ; 생략 가능
(int i) -> { System.out.println(i); }
(int i) -> System.out.println(i)
// 하나뿐인 문장이 return문이면 {}, ; 생략 불가
// 하지만 대부분의 경우 return을 생략하기 때문에 신경 쓸 필요 없음
함수형 인터페이스
단 하나의 추상 메소드만 선언된 인터페이스
함수형 인터페이스 타입의 참조변수로 람다식 참조 가능 (매개변수 개수와 반환타입 일치해야 함)
// 함수형 인터페이스 선언
@FunctionalInterface
interface MyFuntion {
int max(int a, int b); //public abstract는 항상 기본값으로 지정
}
// 람다식의 사용
// 람다식(익명 객체)를 다루기 위해서는 함수형 인터페이스로 참조변수 타입을 지정
// 함수형 인터페이스의 추상 메소드를 구현하여 사용하기 편하게 해주는 역할
MyFuntion f = (a, b) -> a > b ? a : b;
int value = f.max(3, 5);
// 람다식을 함수형 인터페이스 타입의 매개변수로 사용할 수도 있음
void aMethod(MyFunction f) { // 아래와 같은 코드
f.max(3, 5);
}
aMethod(((a, b) -> a > b ? a : b)); // 위와 같은 코드
// 람다식을 함수형 인터페이스 타입의 반환타입으로도 사용가능
MyFunction myMethod() { // 아래와 같은 코드
MyFunction f = (a, b) -> {a > b ? a : b};
return f;
}
MyFunction myMethod() { return (a, b) -> {a > b ? a : b}; } // 위와 같은 코드
java.util.function 패키지
자주 사용되는 다양한 함수형 인터페이스를 제공하는 패키지
매개변수를 3개 이상 받는 함수형 인터페이스는 제공하지 않기 때문에 직접 정의해야 함
// java.lang.Runnable
// 매개변수와 반환값이 모두 없는 경우
void run()
// Supplier<T>
// 매개변수는 없고 반환값은 있는 경우
T get()
// Consumer<T>
// 매개변수만 있고 반환값은 없는 경우
void accept(T t)
// Function<T, R>
// 일반적인 함수로 하나의 매개변수를 받아 결과를 반환
R apply(T t)
// Predicate<T>
// 조건식을 표현하는데 사용하며, 매개변수는 하나고 반환타입은 boolean
boolean test(T t)
// 매개변수가 2개인 함수형 인터페이스
// BiConsumer<T, U>
// 두개의 매개변수만 있고 반환값 없음
void accept(T t, U u)
// BiPredicate<T, U>
// 매개변수 두 개, 반환값은 boolean으로 조건식을 표현할 때 사용
booleadn test(T t, U u)
// BiFunction<T, U, R>
// 두 개의 매개변수로 하나의 결과 반환
R apply(T t, U u)
// 매개변수 타입과 반환타입이 일치하는 함수형 인터페이스
// UnaryOperator<T> 단항연산자
// Function의 자손으로 매개변수와 반환타입이 같음
T apply (T t)
// BinaryOperator<T> 이항연산자
// BiFunction의 자손으로 매개변수와 반환타입이 같음
T apply(T t, T t)
Predicate의 결합
and(&&), or(||), negate(!) 메소드를 사용해 두 개의 Predicate를 하나로 결합 가능
A.negate // == !A
A.and(B) // == A && B
A.or(B) // == A || B
p = A.negate
p.and(B).or(C)
// 결과를 확일할 때는
참조변수명.test(비교할요소)
// 등가비교를 하는 경우에는 isEquals 메소드 사용
Predicate<T> x = Predicate.isEquals(비교될요소).test(비교할요소)
// 조건식 두개 적용
// 조건식 x, y 두 개가 있고 x의 출력과 y의 입력이 같다면
x.andThen(y) // == x를 적용하고 y를 적용
x.compose(y) // == y.andThen(x)
컬렉셤 프레임워크와 함수형 인터페이스
Collection
removeIf() : 조건에 맞는 요소 삭제
List
replaceAll() : 모든 요소 변환하여 대체
Iterable
forEach() : 모든 요소에 작업 수행
Map
compute() : 지정된 키의 값에 작업 수행
computeIfAbsent() : 키가 없으면 작업 수행 후 추가
computeIfPresent() : 지정된 키가 있을 때 작업 수행
merge() : 모든 요소에 병합작업을 수행
forEach() : 모든 요소에 작업을 수행
replaceAll() : 모든 요소에 치환작업을 수행
메소드 참조
하나의 메소드만 호출하는 람다식을 메소드 참조로 간단히 만들 수 있음
// static 메소드 참조
(x) -> 클래스명.메소드(x) >> 클래스명::메소드명
// 인스턴스 메소드 참조
(obj, x) -> obj.method(x) >> 클래스명::메소드명
생성자의 메소드 참조
// 생성자와 메소드 참조
Supplier<MyClass> s = () -> new MyClass(); // 전
Supplier<MyClass> s = MyClass::new; // 후
Function<Integer, MyClass> s = (i) -> new MyClass(i); // 전
Function<Integer, MyClass> s = MyClass::new; // 후
// 배열과 메소드 참조
Function<Integer, int[]> f = x -> new int[x]; // 전
Function<Integer, int[]> f = int[]::new; // 후, 배열 길이도 생략가능