본문 바로가기
2023년 이전/kotlin

kotlin - 자바 함수형 인터페이스 활용

by JeongUPark 2020. 3. 10.
반응형

[출처 -  Kotlin In Action] [아래 내용들은 Kotlin In Action을 공부하면서 스스로 정리한 내용입니다] 

이직을 성공하고 쉬었다 다시 쉬었던 공부를 해야지 하면서 지난 번에 하던 kotlin 정리를 마저 합니다.

 

이번에 정리할 내용은 다음과 같습니다.

 

코틀린은 자바와 호환이 가능합니다. 그래서 자바 API에 코틀린 람다를 활용 하는 방법을 알아 보겠습니다.

 

button.setOnClickListener(new OnClickListener(){
	@Override
    public void onClick(View v){
      //...
    }
});

위와 같이 Button에 Click 발생시 그 이벤트를 캐치할 수 있는 ClickListener를 등록 할 수 있습니다. 그리고 이때 위와 같이 자바는 무명클래스의 인스턴스를 만들어야 합니다.

코틀린에서는 위의 무명클래 인스턴스 대신 람다를 넘겨줄 수 있습니다.

button.setOnClickListener{view -> ...}

 

위와 같이 람다를 사용하여 간단하게 code를 작성할 수 있습니다. 

 

이런 코드가 작동하는 이유는 OnClickListner에 추상 메소드가 단 하나만 있기 때문입니다. 그런 인터페이스를 함수형 인터페이스 또는 SAM 인터페이스라고 합니다. (SAM은 Single abstract method 추사 메소드 라는 뜻입니다.)

자바는 위와 같이 함수형 인터페이스를 활용하는 메소드가 많기 때문에 코틀린에서 함수형 인터페이스를 인자로 취하는 자바 메소드를 호출할 때 람다를 넘길 수 있게 해줍니다.    (자바도 functional interface를 제공합니다. 수정일 2020.11.19)

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

다음 자바 메소드를 코틀린에서 람다를 전달하는 방식으로 변경해 보겠습니다.

void postphoneCoputation(int delay, Runable computation);

위에 메소드는 int완 Runable 2개의 인자를 가집니다. 여기서 Runable 부분을 람다를 사용하여 전달을 하면 컴파일러는 자동으로 람다를 Runable로 변환해줍니다.

변환을 하면

postphoneComputation(1000){println(42)}

delay 에 1000이 computation에 println(42)가 들어가게 됩니다. 또한, 위와 다르게 Runable을 명시적으로 만들 수 있습니다.

postphoneComputation(1000, object:Runable{
	override fun run(){
    	println(42)
    }
})

위의 2 code의 차이점은 두 번째 처럼 객체를 명시적으로 선언하는 경우 메소드를 호출할 때마다 새로운 객체가 생서오딥니다. 하지만 첫 번째 처럼 람다로 정의를 하면 무명객체 메소들르 호출할 때마다 반복 사용합니다.

 

즉, 두 번째 명시적으로 선언하는 경우 호출 할 때마사 객체를 생성하지 않으려면 다음과 같이 Runable 인스턴스를 변수에 저장하여 그 변수를 호출 하면 됩니다.

val runable = Runable{println(42)}
fun handleComputation(){
	postphoneComputation(1000,runable)
}

그리고 첫번째 람다를 사용할 경우에도 반드시 반복사용하는 것은 아닙니다. 람다가 주변 영역의 변수를 사용하게 된다면 컴파일러는 주변 영역 변수를 사용하는 새로운 인스턴스를 생성하게 됩니다.

예를 들어

fun handleComputation(id : string){
	postphoneComputation(1000){println(id)}
}

이럴 경우 새로운 인스턴스를 생성하게 됩니다.

 

이렇게 대부분의 람다와 자바 함수형 인터페이스 사이의 변환은 컴파일러가 자동으로 해줍니다. 하지만 컴파일러가 자동으로 해주지 못할 경우에는 사용가자 직접 변환 해주어야 합니다.

SAM 생성자

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

예를 들어

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

fun main(args: Array<String>) {
    createAllDoneRunnable().run()
}

위와 같이 함수형 인터페이스의 인스턴스를 반환하는 메소드가 있다면 람다를 직접 반환 할 수 없고, 반환하고픈 람다를 SAM 생성자로 감싸야 합니다.

람다로 생성한 함수형 인터페이스 인스턴스를 변수에 저장해야 하는 경우에도 SAM 생성자를 사용할 수 있습니다. 

val listener = OnClickListener { view -> 
    val text = when (view.id) {
        R.id.button1 -> "First Button"
        R.id.button2 -> "Second Button"
        else -> "Unknown button"
    }
    toast(text)  /* <-- "text"의 값을 사용자에게 출력 */
}

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

 

람다는 무명 객체와 달리 인스턴스 자신을 가리키는 this 가 없습니다.

 

반응형