[Kotlin in Action] 25. SAM 생성자

반응형
728x90
반응형

코틀린 람다 전달

함수형 인터페이스를 인자로 원하는 자바 메서드에 코틀린 람다를 전달할 수 있다.

 

자바
void postponeComputation(int delay, Runnable computation);

 

코틀린에서 람다를 위 함수에 넘겨보자.
postponeComputation(1000) { println(42) }

 

컴파일러는 자동으로 람다를 Runnable 인스턴스(Runnable을 구현한 무명 클래스의 인스턴스)로 변환해준다.

무명 클래스에 있는 유일한 추상 메서드를 구현할 때 람다 본문을 메서드 본문으로 사용한다. Runnable은 run()이 그런 추상 메서드다.

 

Runnable을 구현하는 무명 객체를 명시적으로 만들어서 사용할 수도 있다.

 

객체 식을 함수형 인터페이스 구현으로 넘긴다.
postponeComputation(1000, object : Runnable {
    override fun run(){
        println(42)
    }
})

무명 객체는 메서드를 호출할 때마다 새로운 객체를 생성하지만, 함수의 변수에 접근하지 않는 람다에 대응하는 무명 객체를 메서드를 호출할 때마다 반복 사용한다.

 

프로그램 전체에서 Runnable의 인스턴스는 단 하나만 만들어진다.
postponeComputation(1000) { println(42) }

 

모든 handleComputation 호출에 같은 객체를 사용한다.
val runnable = Runnable { println(42) }
fun handleComputation() {
    postponeComputation(1000, runnable) // 모든 handleComputation 호출에 같은 객체를 사용
}

 

람다 안에서 "id" 변수를 포획한다. id 필드로 저장하는 새로운 Runnable 인스턴스를 매번 새로 만들어 사용한다. 람다가 주변 영역의 변수를 포획한다면 매 호출마다 같은 인스턴스를 사용할 수 없게된다. 컴파일러는 매번 주변 영역의 변수를 포획한 새로운 인스턴스를 생성해준다. 

fun handleComputation(id: String) {
    postponeComputation(1000) { println(id) }
}

 

 

 

SAM 생성자

SAM 생성자는 람다를 함수형 인터페이스의 인스턴스로 변환할 수 있게 컴파일러가 자동으로 생성한 함수다. 컴파일러가 자동으로 람다를 함수형 인터페이스 무명 클래스로 바꾸지 못하는 경우 SAM 생성자를 사용할 수 있다.

 

예시) 함수형 인터페이스의 인스턴스를 반환하는 메서드가 있다면 람다를 직접 반환할 수 없고, 반환하고픈 람다를 SAM 생성자로 감싸야한다.

fun createAllDoneRunnable() : Runnable {
    return Runnable { println("All done!") }
}

fun main() {
    createAllDoneRunnable().run()
}

SAM 생성자의 이름은 사용하려는 함수형 인터페이스의 이름과 같다.

SAM 생성자는 그 함수형 인터페이스의 유일한 추상 메서드의 본문에 사용할 람다만을 인자로 받아서 함수형 인터페이스를 구현하는 클래스의 인스턴스를 반환한다.

 

람다로 생성한 함수형 인터페이스 인스턴스를 변수에 저장해야하는 경우에도 SAM 생성자를 사용할 수 있다. 여러 버튼에 같은 리스너를 적용하고 싶다면 다음 리스트처럼 SAM 생성자를 통해 람다를 함수형 인터페이스 인스턴스로 만들어서 변수에 저장해 활용할 수 있다.

val listsner = OnClickListsner { view ->
    val text = when(view.id) { // view.id를 이용해 어떤 버튼이 클릭됐는지 판단한다.
        R.id.button1 -> "First button"
        R.id.button2 -> "Second button"
        else -> "Unknown button"
    }
    toast(text)
} 

button1.setOnClickListener(listener);
button2.setOnClickListener(listener);

 

 

반응형

Designed by JB FACTORY