[기본 개념] 9 | (1.1) 람다식, 람다식 인터페이스

728x90

[기본 개념] 9 | (1.1) 람다식, 람다식 인터페이스

1> 람다식이란?

2> 람다식 작성하기

3> 함수형 인터페이스(Functional Interface)

4 java.util.function패키지

5 Function의 합성과 Predicate의 결합

6 메서드 참조

1. 람다식이란?

 람다식은 메서드를 하나의 식으로 표현한 것이다. 메서드를 람다식으로 표현하면 메서드의 이름과 반환값이 없어지므로, '익명 함수'라고도 한다.

 

int method( ) {

    return (int) (Math.random( ) * 5) + 1) ;

}

 

 위 식을 람다식으로 하면 '( ) -> (int) (Math.random( ) * 5) + 1'로 표현된다. 이처럼 람다식으로 인해 메서드를 변수처럼 다룰 수 있게 되었다.

 

2. 람다식 작성하기

1 람다식은 메서드에서 이름과 반환타입을 제거하고 매개변수 선언부와 몸통{ } 사이에 '->'를 추가한다.

2 매개변수가 하나뿐인 경우에는 괄호( )를 생략할 수 있지만 매개변수의 타입이 있으면 괄호( )를 생략할 수 없다.

3 괄호{ }안의 문장이 하나일 때는 생략할 수 있지만, 문장의 끝에 ';'를 붙이지 않는다. 하지만 괄호 안의 문장이 return문인 경우는 생략할 수 없다.

 

메서드 람다식
    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
    void printVar(String name, int i) {
        System.out.println (name + " = " + i) ;
    }
    (String name, int i) ->
        { System.out.println (name +  " = " + i) ; }
    (name, i) ->
        { System.out.println (name +  " = " + i) ; }
    (name, i) ->
        System.out.println (name +  " = " + i)
    int square(int x) {
        return x * x ;
    }
    (int x) -> x * x
    (x) -> x * x
    x -> x * x
    int roll( ) {
        return (int) (Math.random( ) * 6) ;
    }
    ( ) -> { return (int) (Math.random( ) * 6) ; }
    ( ) -> (int) (Math.random( ) * 6)
    int sumArr(int[ ] arr) {
        int sum = 0 ;
        for (int i : arr)
             sum += i ;
        return sum ;
    }
    (int[ ] arr) -> {
        int sum = 0 ;
        for (int i : arr)
            sum += i ;
        return sum ;
     }

3. 함수형 인터페이스(Functional Interface)

 람다식으로 정의된 익명 객체의 메서드는 람다식과 동등한 메서드가 정의되어 있는 참조변수 f의 타입으로 호출해야 한다.

 

 예를 들어 max( )라는 메서드가 정의된 MyFunction인터페이스가 정의되어 있다고 가정하자.

 

MyFunction f = (int a, int b) -> a > b ? a : b ;    // 익명 객체를 람다식으로 대체

int big = f.max(5, 3) ;            // 익명 객체의 메서드를 호출

 

 이처럼 람다식을 다루기 위한 인터페이스를 '함수형 인터페이스'라고 한다. 함수형 인터페이스에는 오직 하나의 추상 메서드만 정의되어야 하지만 static메서드와 default메서드의 개수에는 제약이 없다.

 

함수형 인터페이스 타입의 매개변수와 반환타입

void aMethod(MyFunction f) {

    f.myMethod( ) ;

}

         . . . 

MyFunction f = ( ) -> System.out.println("myMethod( )") ;

aMethod(f) ;          // 이 줄과 윗 줄을 한 줄로 줄이면, aMethod( ) -> System.out.println("myMethod( )") ;

 

 이렇게 람다식을 매개변수로 지정할 수도 있다.

 

MyFuntcion myMethod( ) {

    MyFunction f = ( ) -> { } ;

    return f ;        // 이 줄과 윗 줄을 한줄로 줄이면, return ( ) -> { } ;

}

 

 이렇게 람다식을 반환할 수도 있다.

 

 이처럼 람다식을 참조변수로 다룰 수 있다는 것은 변수처럼 메서드를 주고받는 것이 가능해진 것이다.

 

람다식의 타입과 형변환

 함수형 인터페이스로 람다식을 참조하는 것이지, 람다식의 타입이 함수형 인터페이스의 타입과 일치하는 것은 아니다. 따라서 대입 연산자의 양변 타입을 일치시키기 위해 형변환이 필요하다.

 

MyFunction f = (MyFunction) (( ) -> { }) ;

 

 이 인터페이스를 구현한 클래스의 객체와 완전 동일하기 때문에 이 형변환은 생략 가능하다.

 

 람다식은 Object타입으로 형변환할 수 없고, 오직 함수형 인터페이스로만 형변환이 가능하다.

 

외부 변수를 참조하는 람다식

 람다식도 익명 클래스의 인스턴스이므로 외부에 선언된 변수에 접근하는 규칙은 익명 클래스와 동일하다.

 

예제/LambdaEx3.java

@FunctionalInterface
interface MyFunction {
    void myMethod();
}

class Outer {
    int val = 10;   // Outer.this.val
    
    class Inner {
        int val = 20;   // this.val
        
        void method(int i) {    // void mehtod(final int i) {
            int val = 30;   // final int val = 30;
//          i = 10;         // error. 상수의 값을 변경할 수 없음

            MyFunction f = () -> {
                System.out.println("i : " + i);
                System.out.println("val : " + val);
                System.out.println("this.val : " + ++this.val);
                System.out.println("Outer.this.val : " + ++Outer.this.val);
            };            
            
            f.myMethod();
        }
    }
}

class LambdaEx3 {
    public static void main(String[] args) {
        Outer outer = new Outer();
        Outer.Inner inner = outer.new Inner();
        inner.method(100);
    }
}
실행결과

i : 100
val : 30
this.val : 21
Outer.this.val : 11

 

 람다식 내에서 참조하는 지역변수는 final이 붙지 않아도 상수로 간주되며 람다식 내에서 i와 val을 참조하고 있으므로 이 변수들의 값을 변경할 수 없다.

 

 또한 외부 지역변수와 같은 이름의 람다식 매개변수는 허용되지 않는다.

 

 

 

 

 

출처 | Java의 정석 (남궁 성)

728x90