어떻게 코틀린 람다를 자바 API에 활용할 수 있는지 살펴보자. 아래와 같이 자바 메소드에 람다를 코드가 있다.

button.setOnClickListener { }

Button 클래스는 setOnClickListener 메소드를 사용해 버튼의 리스너를 설정한다. 이때 인자의 타입은 OnClickListener다.

public class Button {
    public void setOnClickListener(OnClickListener l) {

    }
}

OnClickListener 인터페이스는 onClick이라는 메소드만 선언된 인터페이스다.

public interface OnClickListener {
    void onClick(View v);
}

자바 8 이전의 자바에서는 setOnClickListener 메소드에게 인자로 넘기기 위해 무명 클래스의 인스턴스를 만들어야만 했다.

public class Main {
    public static void main(String[] args) {
        Button button = new Button();
        
        button.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                
            }
        });
    }
}

class Button {
    public void setOnClickListener(OnClickListener l) {

    }
}

interface OnClickListener {
    void onClick(View v);
}

코틀린에서는 무명 클래스 인스턴스 대신 람다를 넘길 수 있다.

button.setOnClickListener { view -> ... }

OnClickListener를 구현하기 위해 사용한 람다에는 view라는 파라미터가 있다. view의 타입은 View다. 이는 onClick 메소드의 인자 타입과 같다.

이런 코드가 작동하는 이유는 OnClickListener에 추상 메소드가 단 하나만 있기 때문이다. 그런 인터페이스를 함수형 인터페이스(functional interface) 또는 SAM 인터페이스라고 한다. SAM은 단일 추상 메소드(single abstract method)라는 뜻이다. 자바 API에는 Runnable이나 Callable과 같은 함수형 인터페이스와 그런 함수형 인터페이스를 활용하는 메소드가 많다.

코틀린은 함수형 인터페이스를 인자로 취하는 자바 메소드를 호출할 때 람다를 넘길 수 있게 해준다. 따라서 코틀린 코드는 무명 클래스 인스턴스를 정의하고 활용할 필요가 없다.

무명 클래스 인스턴스 대신 람다로 구현할 수 있는 것은 Java로 작성한 SAM 인터페이스만 가능하다. Kotlin SAM 인터페이스는 람다로 구현할 수 없다.

interface OnClickListener {
    fun onClick(button: Button)
}

class Button(private val name: String) {
    private lateinit var onClickListener: OnClickListener

    fun setOnClickListener(onClickListener: OnClickListener) {
        this.onClickListener = onClickListener
    }

    fun onClick() {
        onClickListener.onClick(this)
    }
}

fun main() {
    val button = Button("Kotlin")

    button.setOnClickListener {
        // Error occur here, Type mismatch
    }
}

코틀린의 함수 타입

코틀린에서 함수를 인자로 받을 필요가 있는 함수는 함수형 인터페이스가 아니라 함수 타입을 인자 타입으로 사용해야 한다. 코틀린 함수를 사용할 때는 코틀린 컴파일러가 코틀린 람다를 함수형 인터페이스로 변환해주지 않는다. 코틀린 함수 타입의 예시는 아래와 같다.

(int, string) → Unit

자바 메소드에 람다를 인자로 전달