티스토리 뷰

람다식이란?

 

람다식은 익명 함수를 생성하기 위한 식으로, 객체지향 언어보다 함수지향 언어에 더 가깝다. 

람다식은 아래의 형태로 쓰인다.

(매개변수, ...) -> { 실행문; }

예를 들면, 보통 Thread 객체에 실제 실행될 코드를 전달하는 Runnable 인터페이스의 익명 구현 객체를 생성할 때 아래처럼 람다식을 이용할 수 있다.

// 익명 구현 객체 이용
Runnable runnable = new Runnable() {
	public void run() { ... }
};

// 람다식 이용
Runnable runnable = () -> { ... };

위의 예시 코드처럼, 람다식의 형태는 매개변수를 갖는 코드 블록이지만, 런타임 시에는 인터페이스의 익명 구현 객체를 생성한다.

 


함수적 인터페이스 (Functional Interface)

 

자바에서는 엔트리 포인트로 쓰이는 main메소드라 할지라도 메소드를 단독으로 선언할 수 없고, 항상 클래스의 구성 멤버로 존재한다. 따라서 람다식 또한 단순한 메소드의 선언이 아니라 메소드를 가지고 있는 객체를 생성해 낸다. 이 객체는 인터페이스의 익명 구현 객체이다. 

 

모든 인터페이스가 람다식의 타겟이 될 수는 없다. 람다식은 하나의 메소드를 정의하기 때문에, 오로지 단 하나의 추상 메소드가 선언된 인터페이스만이 람다식의 타겟이 된다. 이러한 인터페이스를 함수적 인터페이스(Functional Interface)라고 한다. 

 

함수적 인터페이스를 작성할 때 @FunctionalInterface 어노테이션을 붙여 주면 컴파일러가 컴파일할 때 인터페이스에 두 개 이상의 추상 메소드가 선언되어 있는지 체크하며, 만약 그렇다면 컴파일 오류를 발생시킨다. 

@FunctionalInterface
public interface MyFunctionalInterface {

	public void method1();
    public void method2();	// 이 경우 추상 메소드가 두개 선언되었으므로
    						// 컴파일 에러가 발생한다.
}

람다식과 멤버 및 로컬 변수

 

람다식의 내부에서는 클래스의 필드와 메소드, 그리고 로컬 변수를 사용할 수 있다.

 

람다식과 클래스 멤버

보통의 익명 객체에서 this 키워드를 사용한다면, this는 익명 객체를 의미한다. 하지만 람다식에서 this는 람다식을 실행한 객체를 의미한다. 

public class OuterClass {
	
    public int outerField = 10;
    
    class InnerClass {
    	int innerField = 20;
        
        void method() {
        	MyFunctionalInterface fi = () -> {
            	System.out.println("outerField: " + outerField);
                System.out.println("outerField: " + OuterClass.this.outerField);
                
                System.out.println("innerField: " + innerField);
                System.out.println("innerField: " + this.innerField);
            };
            
            fi.method();
        }
    }
}

 

람다식과 로컬 변수

 

클래스 멤버는 this의 문맥만 잘 주의한다면 사용하는데 제약이 없었다. 하지만 로컬 변수의 경우는 조금 다르다.

메소드 내에서 생성된 익명 구현 객체는, 메소드 실행이 끝나도 힙 영역(객체들이 저장되는 영역)에 존재한다. 하지만 매개 변수나 로컬 변수는 메소드 실행이 끝나면 스택 영역(메소드 관련 정보들이 저장되는 영역)에서 사라지기 때문에, 익명 구현 객체에서 매개 변수나 로컬 변수를 사용하기 위해서는 final 특성을 가져야 한다. 람다식도 마찬가지이다.

 

위 코드처럼 매개변수와 로컬변수의 값을 바꾸려 하면 final이거나 effectively final이어야 한다며 에러를 표시한다.

 


java.util.function 관련 표준 API 인터페이스는 다음 포스트에서...

댓글