Implement Kotlin Interfaces with SAM conversions

vtsen

Vincent Tsen

Posted on December 2, 2022

Implement Kotlin Interfaces with SAM conversions

Different ways of implementing Kotlin interfaces - using subclass conventional method, object keyword and functional (SAM) interfaces

While experimenting LiveData observer, I encountered the following code and I had no idea how it works.

val observer = Observer<T> {
    state.value = it
}
Enter fullscreen mode Exit fullscreen mode

So I looked at the Observer source code in Java. It looks like this.

public interface Observer<T> {
    void onChanged(T t);
}
Enter fullscreen mode Exit fullscreen mode

Observer is an interface, and observer is an object that implements the Observer interface. Wait, where is override fun onChanged(t: T)? How is that possible?

It turns out this is called SAM conversions. SAM stands for Single Abstract Interface.

Before we look into SAM conversions, let's first look at different ways of implementing the interfaces.

Subclass Conventional Method

This is the interface,

interface Observer<T> {
    fun onChanged(t: T)
}
Enter fullscreen mode Exit fullscreen mode

and we subclass it with ObserverImpl

class ObserverImpl<T> : Observer<T> {
    override fun onChanged(t: T) {
        println("$t")
    }
}
Enter fullscreen mode Exit fullscreen mode

To instantiate the ObserverImpl, call the onChanged() function:

val observer = ObserverImpl<String>()
observer.onChanged("test")   
Enter fullscreen mode Exit fullscreen mode

Object Keyword

Other than creating singleton class, object keyword can also be used to implement an interface.

Instead of subclassing, you can implement the Observer interface directly

val observer = object: Observer<String> {
    override fun onChanged(t: String) {
        println("$t")
    }
}
observer.onChanged("test")   
Enter fullscreen mode Exit fullscreen mode

SAM Conversions

Before we can use SAM conversions, you need to add fun keyword in front of the interface.

fun interface Observer<T> {
    fun onChanged(t: T)
}
Enter fullscreen mode Exit fullscreen mode

This is called Functional Interface or Single Abstract Method (SAM) Interface. In other word, the interface must have only ONE function/method.

To implement the Observer interface, you use the lambda expression.

val observer = Observer<String> {
    println("$it")
}
observer.onChanged("test") 
Enter fullscreen mode Exit fullscreen mode

This lambda expression is basically the override onChanged() function that you want to implement. it is the implement argument.

If onChanged() has 2 arguments,

fun interface Observer<T> {
    fun onChanged(arg1: T, arg2: T)
}
Enter fullscreen mode Exit fullscreen mode

it is going to be like this

val observer = Observer<String> { arg1, arg2 ->
    println("$arg1,$arg2")
}
observer.onChanged("test1", "test2")  
Enter fullscreen mode Exit fullscreen mode

Conclusion

Well, SAM conversions are new to me. After getting used to it, I just need to imagine the lambda expression as the override function of the interface I want to implement.

It uses less code than object keyword because you no longer need to explicitly declare the override function. The limitation is the interface must contain only one interface.


Originally published at https://vtsen.hashnode.dev.

💖 💪 🙅 🚩
vtsen
Vincent Tsen

Posted on December 2, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related