코틀린의 람다식을 기존 자바 API에도 사용할 수 있으며, 호환이 가능하기 때문에 이러한 코틀린 람다를 자바 API에 활용하는 방법에 대해서 살펴보겠습니다.
우리는 자바 8 이전까지는 클릭 이벤트 처리를 위해서 아래와 같이 setOnClickListener 메소드에 파라미터로 무명 클래스 인스턴스를 넘겨야만 했습니다.
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
}
});
코틀린에서는 무명 클래스 인스턴스 대신 람다를 넘길 수 있습니다.
물론, 자바에서 처럼 무명 클래스를 사용해도 됩니다. (코틀린의 object 를 사용하면 되겠죠?)
/* 코틀린 람다 사용 */
button.setOnClickListener { view -> ... }
/* 무명 클래스 인스턴스 object 사용 */
button.setOnClickListener(object : View.OnClickListener {
override fun onClick(view: View) {
...
}
})
이런 코드가 작동하는 이유는 OnClickListener에 추상 메소드가 단 하나만 있기 때문입니다.
public interface OnClickListener {
void onClick(View view); // {view -> ...} 대응
}
즉, 오직 하나의 추상 메소드를 가진 인터페이스를 함수형 인터페이스(functional interface) 또는 SAM 인터페이스라고 합니다. (SAM = Single Abstract Method)
자바 메소드에 파라미터로 람다 전달하기
함수형 인터페이스를 파라미터로 받는 자바의 메소드에 코틀린 람다를 전달하는 방식을 알아보겠습니다.
/* 자바 */
void post(int delay, Runnable run)
/* 코틀린 */
post(1000) { println("람다로 전달") }
위에서 Runnable 인스턴스를 람다로 사용하여 전달하면, 컴파일러는 자동으로 람다를 Runnable 인스턴스로 변환해줍니다.
당연히 object를 사용하여 무명 클래스로도 호출 할 수 있습니다.
/* 무명 클래스로 명시적 선언 */
post(1000, object : Runnable {
override fun run() {
print("object로 명시적 선언")
}
})
하지만 람다와 무명 클래스 사이에는 큰 차이가 있습니다.
무명 클래스를 사용 하는 경우에는 메소드를 호출할 때마다 새로운 객체를 계속 생성하여 사용합니다.
반면에 람다는 단 한번만 객체를 생성한 후 재사용하기 때문에 훨씬 효율적입니다.
post(1000) { ... } //전역변수로 컴파일되므로 단 하나의 인스턴스만 생성됩니다.
SAM 생성자 : 람다를 함수형 인터페이스로 명시적 변경
SAM 생성자는 람다를 함수형 인터페이스로 변환할 수 있게 컴파일러가 자동으로 생성한 함수입니다.
컴파일러가 자동으로 람다를 함수형 인터페이스로 바꾸지 못하는 경우에는 직접 SAM 생성자를 사용할 수 있습니다.
/* SAM 생성자를 사용해 값 반환하기 */
fun createAllDoneRunnable(): Runnable {
return Runnable { println("Done!") }
}
>>> createAllDoneRunnable().run()
Done!
createAllDoneRunnable 는 Runnable 객체 자체를 반환하는 메소드입니다.
SAM 생성자의 이름은 사용하려는 함수형 인터페이스의 이름과 같습니다.
함수형 인터페이스의 유일한 추상 메소드(위의 예제의 경우 run) 의 본문에 사용할 람다만을 인자로 받아서 인스턴스를 반환합니다.
람다로 생성한 함수형 인터페이스를 변수에 저장해야 하는 경우에도 SAM 생성자를 사용할 수 있습니다.
예를 들어, 여러 버튼에 같은 클릭 리스너를 적용하고 싶다면 아래처럼 SAM 생성자를 통해 람다를 함수형 인터페이스로 만들어서 변수에 저장해 활용할 수 있습니다.
/* SAM 생성자를 사용해 리스너 재사용 하기 */
val listener = View.OnClickListener { view ->
val text = when (view.id) {
R.id.button1 -> "First Button"
R.id.button2 -> "Second Button"
else -> "Unknown Button"
}
Toast.makeText(this, text, Toast.LENGTH_SHORT).show()
}
button1,setOnClickListener(listener)
button2,setOnClickListener(listener)
단! 람다식의 this는 자기 자신을 가리키지 않기 때문에, 자기 자신을 컨트롤해야 하는 경우에는 람다식이 아닌 무명 클래스를 사용해서 구현해야 합니다.
'코틀린' 카테고리의 다른 글
코틀린(Kotlin) - lambda with receiver(수신 객체 지정 람다) : with, apply (0) | 2021.03.16 |
---|---|
안드로이드 코루틴 기본 개념과 활용까지의 모든 것! (3) | 2021.03.08 |
코틀린(Kotlin) - 지연 계산(lazy) 컬렉션 연산 : Sequence (0) | 2020.04.24 |
코틀린(Kotlin) - 컬렉션 API : filter, map, all, any, count, find, groupBy, flatMap, flatten (1) | 2020.04.03 |
코틀린(Kotlin) - 초간단 파일 저장 방법! (1) | 2020.03.25 |