[코틀린] SAM (함수형 인터페이스)

berry·2023년 4월 8일
0

SAM 이란?

SAM은 Single Abstract Method의 줄임말로, 오직 하나의 추상 메소드를 가지고 있는 인터페이스를 뜻한다.
함수형 인터페이스라고도 부른다.

대표적인 예

  • View.java의 OnClickListener
public interface OnClickListener {
    /**
     * Called when a view has been clicked.
     *
     * @param v The view that was clicked.
     */
    void onClick(View v);
}

OnClickListener 인터페이스는 추상메소드 onClick 하나만 가지고 있다.

SAM 변환

  • 자바 8 이전에는 함수형 인터페이스를 인자로 받는 Java 함수를 호출할 경우 인터페이스를 구현한 익명 클래스 인스턴스를 만들어서 넘겨줘야 했다.
  • 자바 8 이후 인터페이스 객체 대신 람다를 넘길 수 있다. 이를 SAM 변환이라고 한다.

대표적인 예

함수형 인터페이스를 인자로 받는 자바 함수의 대표적인 예로는 View.setOnClickListener 가 있다.

public void setOnClickListener(@Nullable OnClickListener l) {
             ...
}

자바 8 이전에서는 아래 코드 처럼 익명 객체를 생성해서 전달 해야 했다.

button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {//익명객체 생성 전달}
});

그러나 자바 8 이후와 코틀린에서는 익명 객체를 생성하는 대신 람다를 전달 할 수 있다.

코틀린

button.setOnClickListener { println("익명객체 대신 람다를 넘김 ${it.id} ") }

자바
Java 8 이후로 사용할 수 있다.

button.setOnClickListener(v -> Log.i("syTest","Java 에서의 람다"));

어떻게 이런 동작이 가능할까?

인터페이스 객체 대신 람다를 함수형 인터페이스의 인자로 전달 할 때, 내부적으로 컴파일러가 람다에 대해 익명 객체를 생성해서 메소드에 넘긴다.

람다를 사용하지 않고 object 를 이용해 명시적으로 익명 객체를 넘길수도 있지만 이렇게 하면 해당 코드를 수행할 때마다 익명 객체가 새로 생성된다.
람다를 이용한다면 프로그램 전체에서 객체는 하나만 만들어진다. (람다가 변수를 포획했을 때는 예외적으로 매번 생성한다. 왜냐하면 포획할 변수가 매번 바뀔 수 있기 때문)

SAM 변환 주의사항

주의해야될 점은 SAM 변환은 자바에서 작성한 인터페이스일 때만 동작한다는 것이다.

코틀린에서 하나의 추상 메소드만 있는 인터페이스를 생성하고, 그 인터페이스를 인자로 받는 함수에 람다를 넘기려고 하면 오류가 발생한다.
코틀린에서 SAM 변환을 지원하지 않는 이유는 코틀린에서는 함수를 파라미터로 사용할 수 있기 때문이다.

만약 코틀린에서 SAM 변환을 사용하고 싶다면, 기존 코틀린의 인터페이스 앞에 fun 키워드를 붙여주면 된다.
그러면 해당 인터페이스는 함수형 인터페이스가 되고 SAM 변환이 동일하게 실행된다.

fun main(){
	// 방법 1
    doSomething{println("a")}
    // 방법 2
    val practice = Practice{println("a")}
    doSomething(practice)
}

fun doSomething(practice: Practice){
    practice.a()
}

fun interface Practice{
    fun a()
}

출처

profile
공부 내용 기록

0개의 댓글