자바의 함수형 인터페이스 사용: 단일 추상 메서드

유우선·2026년 2월 3일

Kotlin Study📚

목록 보기
10/32

개요

  • 코틀린은 자바 API와 완전히 호환됨
  • 자바 8 이전에는 onClickListener 인터페이스 구현을 위해 익명 클래스 인스턴스를 setOnClickListener에 전달해야 했음
    button.setOnClickListener(new onClickListener() {
    	@Override
    	public void onClick(View v) {
    		/*...*/
    	}
    });
  • 자바 8 이후에는 어느정도 간소화가 가능했음
    button.setOnClickListener(view -> { /*...*/ });
  • 코틀린에서는 단순히 람다만 전달하면 됨
    button.setOnClickListener{ view -> /*...*/ }
  • onClickListener 인터페이스 안에 추상 메서드가 단 하나뿐이어서 람다 사용이 가능함
    • 이런 인터페이스를 “함수형 인터페이스” 또는 “단일 추상 메서드 인터페이스”라고 함
  • 자바 API 에는 Runnable, Callable 등의 함수형 인터페이스가 많음
    • 따라서 코틀린에서 람다를 자바 메서드에 사용할 수 있다.

람다를 자바 메서드의 파라미터로 전달

함수형 인터페이스를 파라미터로 받는 모든 자바 메서드에 람다를 전달할 수 있음

void postponeComputation(int delay, Runnable computation);

코틀린에서 이 메서드를 호출 할 때 람다를 인자로 보낼 수 있음

postponeComputation(1000) { println(42) }
  • 컴파일러가 자동으로 람다를 Runnable 인스턴스로 변환해줌
  • Runnable 인스턴스 → “Runable을 구현하는 익명 클래스의 인스턴스”

Runnable을 명시적으로 구현하는 익명 객체를 만들어 사용할 수도 있음

postponeComputation(1000, object: Runnable {
	override fun run() {
		println(42)
	}
})
  • 명시적으로 객체를 선언하면 함수를 호출할 때마다 새 인스턴스가 생김
  • 람다를 사용하면 새 인스턴스를 생성하는 대신 람다에 해당하는 익명 객체를 재사용함
    • 람다가 선언된 함수의 변수를 캡처하지 않는다면

람다의 익명 클래스 인스턴스 재사용

  • 함수형 인터페이스를 받는 자바 메서드에서는 인스턴스를 재사용
  • 코틀린 확장함수를 사용하는 컬렉션에서는 인스턴스를 재사용할 수 없음
    • inline 표시가 되어있는 코틀린 함수에 람다를 전달하면 익명 클래스가 생성되지 않음

SAM 변환: 람다를 함수형 인터페이스로 명시적 변환

SAM 생성자 → 람다를 단일 추상 메서드 인터페이스의 인스턴스로 명시적 반환을 해줌

컴파일러가 자동으로 변환해주지 못하는 상황에서 사용

  • 함수형 인터페이스의 인스턴스를 반환하는 함수가 있다면 람다를 직접 반환할 수 없음
  1. 값을 반환하기 위해 SAM 생성자 사용

    fun createAllDoeRunnable(): Runnable {
    	return Runnable { println("All done!") }
    }
    
    fun main() {
    	createAllDoneRunnable().run()
    	//All done!
    }
    • SAM 생서자의 이름 → 사용하려는 함수형 인터페이스의 이름과 같음
    • 하나의 인자만 받아 함수형 인터페이스를 구현하는 클래스의 인스턴스를 반환함
  2. 람다로 생성한 함수형 인터페이스 인스턴스를 변수에 저장

    val listener = onClickListener { view ->
    	val text = when (view.id) {
    		button1.id -> "First button"
    		button2.id -> "Second button"
    		else -> "Unknown button"
    	}
    	toast(text)
    }
    button1.setOnClickListener(listener)
    button2.setOnClickListener(listener)

람다와 리스너 등록/해제

  • 람다에는 익명 클래스와 다르게 자기 자신을 가리키는 this를 사용할 수 없음
    • 람다는 코드 블럭일 뿐 객체가 아니기 때문에 람다를 참조할 수 없기 때문
    • 람다 안에서의 this는 그 람다가 선언된 클래스의 인스턴스를 가리킴
  • 이벤트 리스너가 자기 자신의 리스너 등록을 해제해야 한다면 람다를 사용할 수 없음
    • 람다 대신 익명 객체를 사용해 리스너를 구현해야 함

0개의 댓글