Notice
Recent Posts
Recent Comments
Link
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
Archives
Today
Total
관리 메뉴

희디비

[자바의 정석] 람다 본문

Java

[자바의 정석] 람다

희디비 2023. 10. 30. 11:42

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