1.람다식
람다식(Lambda expression)은 메서드를 하나의 식(expression)으로 표현한것이다.
메서드를 람다식으로 표현하면 메서드의 이름과 반환값이 없어지므로 람다식을 "익명 함수" 라고도 한다.
1 - 2 람다식 작성하기
메서드에서 이름과 반환타입을 제거하고 매개변수 선언부와 몸통 { } 사이에 -> 를 추가합니다.
int max(int a, int b) {
return a > b ? a : b;
}
위의 식을 람다식으로 바꾸면
(int a, int b) -> { return a > b ? a : b; }
(int a, int b) -> a > b ? a : b
(a, b) -> a > b ? a : b
return문 대신 '식'으로 대신가능하며 '식' 이므로 끝에 " ; " 을 붙이지 않습니다.
매개변수의 타입은 추론이 가능한경우 생략가능하며, 대부분 생략 가능하다.
반환타입이 없는경우도 추론이 가능하기 때문입니다.
(a) -> a * a > a -> a * a //Ok
(int a) -> a * a > int a -> a * a //Error
// 매개변수의 타입이 있다면 생략이 불가능 합니다.
(int a, int b) -> { return a > b ? a : b; } //OK
(int a, int b) -> return a > b ? a : b //Error
// return 문의 경우 { } 를 생략할 수 없습니다.
1 - 3 함수형 인터페이스 (Functional Interface)
람다식은 익명 클래스의 객체와 동등하다.
(int a, int b) -> a > b ? a : b
▼
new Object() {
int max(int a, int b){
return a > b ? a : b ;
}
}
그렇다면 매소드를 어떻게 호출할까?
참조변수를 이용해 메서드를 호출해보자
MyFunction f = new MyFunction() {
public int max (int a, int b) {
return a > b ? a : b;
}
};
int big = f.max(5, 3); // 익명 객체의 메서드를 호출합니다.
Myfunction은 인터페이스이며 추상메서드로 max 메서드를 가지고있습니다.
위 익명 객체를 람다식으로 바꾸면 아래와 같이 대체됩니다.
MyFunction f = (int a, int b) -> a > b ? a : b;
int big = f.max(5.3);
익명 객체를 람다식으로 대체 가능한이유는 람다식도 익명객체이고, Myfunction인터페이스를 구현한
메서드와 람다식의 매개변수 타입과 개수 반환값이 일치하기 때문입니다.
람다식을 다루기 위한 인터페이스를 " 함수형 인터페이스"(Functional interface) 라고 합니다.
함수형 인터페이스에는 오직 하나의 추상메서드만 있어야합니다.
그래야 인터페이스의 메서드와 1:1로 연결되기 때문입니다.
하지만 static, default 메소드는 제한이 없습니다.
@Funtionalinterface 어노테이션을 붙이면 컴파일러가 올바르게 정의했는지 확인해줍니다.
함수형 인터페이스 타입 매개변수와 반환타입
람다식을 참조변수로 다룰수 있다는 것은 메서드를 통해 람다식을 주고 받을수 있으며,
변수처럼 메서드를 주고받을수 있다는것을 의미합니다.
@FunctionalInterface
interface MyFunction {
void talk();
}
class LamdaEx1 {
static void execute(Myfunction f){
f.talk();
}
static MyFunction getMyFunction() {
MyFunction f = () -> System.out.println("f3.talk()");
return f;
}
public static void main(String[] args) {
// 람다식으로 구현
MyFunction f1 = () -> System.out.println("f1.talk()");
//익명 클래스로 구현
MyFunction f2 = new MyFunction(){
public void talk(){
System.out.println("f2.talk()");
}
};
MyFunction f3 = getMyFunction();
f1.talk();
f2.talk();
f3.talk();
execute(f1);
// 매개변수인 MyFunction을 람다로 구현
execute( () -> System.out.println("talk()") );
}
}
람다식의 타입과 형변환
람다식의 타입이 함수형 인터페이스와 일치하는것은 아니다. 람다식은 익명객체이고 익명객체는 타입이없다 (!!)
정확히는 있지만 컴파일러가 정의한다. 그레서 양변의 타입일치를 위해 형변환이 필요하다.
MyFunction f = (MyFunction) ( () -> {} );
인터페이스를 구현한 객체와 완전히 동일하기때문에 형변환을 허용합니다.
이 형변환을 생략가능합니다 ( 아하! )
람다식은 객체지만 바로 Object 타입으로 변환할수 없다.
굳이 Object 타입으로 변환하려면 (Object) (함수형 인터페이스) ( () -> { } ); 로 변환해야한다.
java.util.function 패키지
대부분의 매서드는 매개변수 (0~2개) 반환값은 없거나 한개이다( 제네릭 사용시 매개변수, 반환타입 상관x)
재사용성, 유지보수 측면에서 패키지의 인터페이스를 사용하자!
함수형 인터페이스 | 메서드 | 설명 |
java.lang.Runaable | void run() | 매개변수x, 반환값 x |
Supplier<T> | T get() | 매개변수x, 반환값o |
Consumer<T> | void accept(T t) | 매개변수o, 반환값o |
Function<T,R> | R apply (T t) | 일반적인 함수 |
Predicate<T> | boolean test(T t) | 조건식을 표한하는데 사용됨 매개변수 1개, 반환타입boolean |
'Java' 카테고리의 다른 글
[Java] LockSupprot, ReentrantLock (1) | 2024.11.19 |
---|---|
[Java] 메모리 가시성, 임계 영역 (4) | 2024.11.15 |
[Java] Join, Interrupt, Yield (0) | 2024.11.12 |
[Java] 스레드의 생성과 생명주기 (0) | 2024.11.10 |
[Java] 프로세스와 스레드 (4) | 2024.11.09 |