본문 바로가기
개발새발/코틀린

[코틀린/Kotlin] SAM; Single Abstract Method

by 조희우 2025. 9. 10.

SAM; Single Abstract Method

  • 단 하나의 추상 메서드만 가진 인터페이스 또는 추상 클래스
  • Java에서는 주로 함수형 인터페이스(Fuctional Interface)라고 호칭
  • Kotlin에서도 Java 함수형 인터페이스와 함께 사용할 때 SAM 변환을 지원

JAVA

@FunctionalInterface
interface Runnable {
    void run();
}
  • Runnable 인터페이스: 추상 메서드 run() 하나

[Java8 이후 람다 구현 가능]

public class Main {
    public static void main(String[] args) {
        Runnable task = () -> System.out.println("Hello from Runnable");
        task.run();
    }
}

Kotlin

SAM 변환

Java 함수형 인터페이스에 한해서 SAM으로 자동 변환

순수 Kotlin 인터페이스에서는 불가능하며 대신 fun interface 사용

fun main() {
    val thread = Thread { println("Hello from Thread") }
    thread.start()
}
  • Thread는 Runnable 타입을 받음 → Kotlin이 람다를 Runnable로 자동 변환

SAM 직접 생성

Kotlin 1.4 이후부터 fun interface 키워드로 SAM 정의 가능

fun interface MyFunction {
    fun invoke(x: Int): Int
}

fun main() {
    val doubler = MyFunction { it * 2 }  // SAM 변환
    println(doubler.invoke(5)) // 10
}
  • fun interface: 반드시 하나의 추상 메서드만 선언 가능
  • 람다식으로 구현 가능

Java API 사용 이유

Java 라이브러리와 호환성 + 재사용성 + 의도표현


  1. Java와의 상호운용성: Interoperability
    Kotlin은 JVM 위에서 동작아므로 Java 라이브러리나 프레임워크를 사용되며 Java API들이 이미 SAM으로 설계
  2. 표준화된 역할/의도
    람다로 직접 구현도 가능하지만 Runnable, Collable, Consumer 등의 인터페이스는 코드의 의도를 명확히 표현
  3. // 람다: 코드를 이해하는데 시간이 걸림 val job = { println("Hello") } // Runnable: 스레드에서 실행될 작업이 명확해짐 val job: Runnable = Runnable { println("Hello") }
  4. 라이브러리, 프레임워크와의 일관성
    많은 Java API가 SAM을 매개변수로 받도록 설계되어있어 Kotlin도 그에 맞춰 SAM과 연결이 필요

장점

  • 코드 간견화: 불필요한 익명 클래스 작성 없이 람다식으로 구현 가능
  • Java API와 호환: Kotlin에서 Java 라이브러리 활용 시 자연스럽게 람다 적용
  • 함수형 스타일 지원: 함수형 프로그래밍 문법에 적절

주의점

  • Kotlin 순수 인터페이스에는 SAM 변환 불가능: fun interface 선언 필용
  • 추상 메서드는 하나만 가능: 멤버 메서드나 default 메서드는 여러개 있어도 가능
  • SAM 변환은 런타임 오버헤드 없음: 컴파일 시 람다는 해당 인터페이스 구현체로 변환