Java 람다식

1. 람다식


  • y = f(x) 형태의 함수로 구성된 프로그래밍 기법
  • 데이터 포장 객체를 생성후 처리하는 것 보다 데이터를 바로 처리하는 것이 속도에 유리
  • 자바는 람다식을 함수적 인터페이스의 익명 구현 객체로 취급
    • 함수적 인터페이스 : 한 개의 메서드를 가지고 있는 인터페이스
Runnable runnable = new Runnable(){
    public void run(){ ...} // 익명 구현 객체
}

Runnable runnable = () -> {...} // 람다식
// () 는 run의 ()를 의미하고, {}는 run 뒤의 중괄호를 의미

매개변수는 ()로 들어오고 코드 블록은 {}이다. 람다식은 인터페이스의 메서드를 구현한 익명 구현 객체가 된다.

2. 람다식 기본 문법


(타입 매개변수,..) -> {실행문;...}
(int a) -> { System.out.println(a); }

매개 타입은 런타임시 대입값에 따라 타입 자동 인식 -> 생략 가능
(a) -> { System.out.println(a); }

매개변수가 하나일 경우 () 생략 가능
a -> { System.out.println(a); }

실행문이 하나일 경우 중괄호 생략 가능
a -> System.out.println(a); 

매개변수가 없다면 괄호 생략 불가능
() -> System.out.println(a);

리턴값이 있는 경우 return  사용
(x,y) -> { return x+y; }

중괄호에 return 문만 있다면 리턴 생략 가능
(x,y) -> return x+y; 


3. 타겟 타입과 함수적 인터페이스


타겟 타입

인터페이스 변수 = 람다식 // 인터페이스가 타겟타입
  • 람다식이 대입되는 인터페이스
  • 익명 구현 객체를 만들 때 사용할 인터페이스

함수적 인터페이스

  • 모든 인터페이스는 람다식의 타겟 타입이 될 수 없다.
    • 람다식은 하나의 메서드를 정의하기 때문
    • 하나의 추상 메서드만 선언된 인터페이스만 타겟 타입이 될 수 있음
  • 함수적 인터페이스
    • 하나의 메서드만 선언된 인터페이스
  • @FunctionalInterface 애노테이션
    • 하나의 추상 메서드만을 가지는지 컴파일러가 체크
    • 두 개 이상이면 컴파일 오류 발생
    • 없어도 되긴 함
@FunctionalInterface
public interface Myfun{
    public void method();
}

매개변수가 있는 람다식
Myfun fi = (x) -> {...}
fi.method(5);

리턴값이 있는 람다식
Myfun fi = (x) -> {... return ;}
int result = fi.method(5);


4. 클래스 멤버와 로컬 변수 사용


  • 클래스 멤버 사용
    • 람다식 실행 블록에는 클래스의 멤버인 필드와 메서드를 제약없이 사용할 수 있다.
    • 람다식 실행 블록 내에서 this는 람다식을 실행한 객체의 참조이다.
  • 로컬 변수 사용
    • 람다식은 함수적 인터페이스의 익명 구현 객체를 생성한다
    • 람다식에서 사용하는 외부 로컬 변수는 final 특성을 갖는다.
public class Ex{
    public int out = 10; // 람다식 내부 사용으로 final 특성을 가짐

    class Inner {
        int inner =20; // 람다식 내부 사용으로 final 특성을 가짐

        void method(){
            Myfun fi = ()->{
                System.out.println(out); // 10
                System.out.println(Ex.this.out); // 10
                // Ex.this는 Ex를 가리킴

                System.out.println(inner); // 20
                System.out.println(this.inner); // 20
                // this는 Inner을 가리킴
            }
        }
    }
}


5. 메서드 참조


(x,y) -> Math.max(x,y); // 람다식

Math::max; // 메서드 참조

IntBinaryOperator 인터페이스는 두개의 int 매개값을 받아 int값을 리턴하는 메서드를 가짐
동일한 매개값과 리턴타입을 갖는 Math클래스의 max 메서드를 참조 가능
IntBinaryOperator operator = Math::max
  • 메서드를 참조해서 매개변수의 정보 및 리턴타입을 알아내어 람다식에서 불필요한 매개변수를 제거하는 것이 목적
  • 메서드 참조도 람다식과 마찬가지로 인터페이스의 익명 구현 객체로 생성됨
    • 타겟 타입에서 추상 메서드의 매개변수 및 리턴 타입에 따라 메서드 참조도 달라짐


정적 메서드와 인스턴스 메서드 참조

public class Calcu{
    public static int staticMethod(int x, int y){
        return x+y;
    }
    public int instanceMethod(int x, int y){
        return x+y;
    }
}

// 정적 메서드
IntBinaryOperator operator;
operator = Calcu::staticMethod;

// 인스턴스 메서드
Calcu a = new Calcu();
operator = a::instanceMethod;
  • 정적 메서드 참조
    • 클래스 :: 메서드
    • 정적 메서드는 인스턴스 생성이 필요 없기 때문
  • 인스턴스 메서드 참조
    • 참조변수 :: 메서드
    • 인스턴스 메서드는 인스턴스 생성이 필요하기 때문


매개변수의 메서드 참조

(a,b) -> {a.instanceMethod(b)}
a클래스::instanceMethod // a클래스의 instanceMethod를 호출하여 매개값으로 b를 준다.


생성자 참조

(a,b) -> {return new 클래스(a,b)}
클래스::new // 클래스의 생성자에 a,b가 매개변수로 들어간다.

© 2021. By Backtony