Kotlin 함수형 인터페이스와 SAM 생성자

김희망·2023년 4월 8일
1

개발일지

목록 보기
8/17

개요

코틀린 인 액션 책 내용중 람다 파트에서 함수를 인자로 사용했을때, 무명객체를 사용했을때 차이와 여러 중요해보이는 지식들이 많아 글을 정리해보려고 한다.

람다 Lambda

람다는 함수형 프로그래밍에서 함수를 간결하게 표현하는 방법 중 하나다.

보통 함수를 정의하고 호출하는 과정을 생략하고, 함수의 내용만을 직접 표현한다.

람다는 함수형 인터페이스를 구현하는 익명 함수다. 즉, 람다는 함수형 인터페이스를 구현하기 위한 구현체로서, 람다 식을 사용해 구현된 함수형 인터페이스는 일반적인 인터페이스를 구현한 클래스와 같이 사용될 수 있다.

무명 객체

자바에서는 과거 클릭과 같은 이벤트 처리를 위해서는 인자로 무명객체를 생성해 받아야했다.

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

코틀린은 무명 객체 대신에 람다를 넘길 수 있다. (물론 자바처럼 무명 객체 object를 사용해서 넘겨도 된다)

button.setOnClickListener { view -> ... }

button.setOnClickListener(object : View.OnClickListener {
    override fun onClick(view: View) {
        ...
    }
})

이런 코드가 동작하는 이유는 OnClickListener클래스가 단 하나의 추상 메서드를 가지고 있기 때문이다. 즉, 이러한 오직 하나의 추상 메서드만 가지고있는 인터페이스를 SAM(Single Abstact Method) 인터페이스 또는 함수형 인터페이스라고 한다.

SAM 생성자

SAM 생성자는 말 그대로 SAM 인터페이스를 구현하는 객체를 생성할 때 사용된다.

val listener = OnClickListener { 
    // onClick 구현
}

위의 코드는 SAM 생성자를 사용해 작성한 OnClikListner에 구현이다.

SAM 생성자는 SAM 인터페이스의 이름 뒤에 중괄호를 붙이고 인자로 전달받을 람다식을 작성한다. 이렇게 작성하면 컴파일러가 자동으로 함수형 인터페이스를 구현하는 객체를 생성하고 람다식을 이 객체의 추상 메서드에 대응하는 메서드로 구현한다.

SAM 생성자는 여러 개의 인자를 가진 SAM 인터페이스에 대해서도 동작한다. 단,SAM 인터페이스의 추상 메서드의 인자 이름은 람다식에서 사용할 이름과 일치해야한다.

무명 객체 사용 vs 람다 사용

무명 클래스를 사용하는 경우에는 메소드를 호출할 때마다 새로운 객체 인스턴스를 생성해 사용한다.

반면에 람다는 단 한번만 객체를 생성한 후 재사용한다 즉, 훨씬 효율적이다.

SAM 생성자를 사용할 때 자바에서

SAM 생성자는 코틀린에서만 지원하는 기능으로 자바에서는 SAM 생성자에 대한 개념이 없다. 자바에서는 람다식을 사용할 때, 함수형 인터페이스를 직접 작성하거나, 자바에서 제공하는 미리 정의된 함수형 인터페이스를 사용한다. 이 때, 함수형 인터페이스를 구현하는 익명 클래스를 생성해서 람다식을 전달한다

예시로 Runnable 인터페이스는 매개 변수와 반환값이 없는 함수를 표현하며, 이 인터페이스를 람다식으로 구현하면 다음과 같이 쓸 수 있다.

Runnable r = () -> System.out.println("Hello, World!");

이렇게 작성된 람다 식은 r 변수에 할당되어진다.

즉 코틀린에서 인자로 람다를 보냈을때 자바에서는 무명 객체가 생성되어 전해진다.

여기서 어라? 람다는 한번만 객체를 생성한 후 재사용을 하는데 자바에서는 무명 객체가 생성된다?

자바에서는 이러한 성능 문제를 해결하기 위해서 람다식을 stream이나 함수형 인터페이스를 사용하는 메서드의 매개변수로 전달하는 방식을 사용할 수 있다. 이 경우, 람다식이 객체 생성을 한 번만 수행하고 재사용할 수 있으며, 성능 저하를 해결할 수 있다.

또 자바 8 이후부터는 Supplier와 같은 인터페이스를 사용해, 객체를 생성하는 코드를 람다식으로 대체할 수 있다. 이 방법을 사용하면 필요한 시점에 객체를 생성하고, 필요하지 않은 경우 객체를 생성하지 않도록 할 수 있다.

주의

코틀린에서 람다식의 this는 자기 자신이 아닌, 해당 람다식을 둘러싼 객체를 가르킨다. (최상위에 써있는 람다는 어떤 것도 가르키지 않는다)

반대로 자바 람다는 최상위에 써져있으면 자신을 구현한 무명 객체를 가르킨다. 

마무리

마무리하며 무명 객체와 함수형 인터페이스 SAM 생성자에 대해서 알아보았다. 정말 중요한 개념이라고 생각하고 람다는 개발시대의 혁신을 일으킨 문법이라고 생각되며 다들 즐거운 프로그래밍 생활을 보내길 바란다

profile
소프트웨어 엔지니어, 김희망입니다.

0개의 댓글