Post

Functional Interfaces in Kotlin

Learn what functional interfaces are and how to use them in Kotlin.

Interfaces with a single function in Kotlin can be converted to functional interfaces. Kotlin will use SAM (Single Abstract Method) conversion to make it possible to use a lambda instead of creating a class or extending an object, removing boilerplate code and making it more readable.

Creating functional interfaces

Let’s take the following PageObserver interface as an example. It’s a standard interface with a single function and an instance of it needs to be passed to the registerPageObserver function.

1
2
3
4
5
6
7
8
9
interface PageObserver {
  fun onPageVisible(pageIndex: Int)
}

registerPageObserver(object : PageObserver {
  override fun onPageVisible(pageIndex: Int) {
    // do something
  }
})

We can simplify the code by turning the PageObserver interface into a functional interface. Functional interfaces can be defined by prepending a fun modifier before the interface keyword:

1
2
3
fun interface PageObserver {
  fun onPageVisible(pageIndex: Int)
}

We can now replace the creation of an instance of this interface with a simple lambda function:

1
2
3
registerPageObserver { pageIndex ->
  // do something
}

If trying to add the fun modifier to an interface with more than one function, the compiler will throw an error “Fun interfaces must have exactly one abstract method”.

Java and Kotlin interoperability

Kotlin also supports SAM conversions for Java interfaces. This is why for example on Android you can use the lambda version of existing system Java interfaces like View.OnClickListener.

1
2
3
4
5
6
7
8
public interface OnClickListener {
  void onClick(View v);
}

val view = findViewById<Button>(R.id.btn_start)
view.setOnClickListener { view ->
  // SAM converted lamba
}

Conclusion

Functional interfaces in Kotlin are a simple construct that can improve the readability and maintainability of your codebase by removing boilerplate code.

It’s a good construct to be aware of, but you should only use it when it’s needed as there is runtime overhead involved due to conversion.

Alternatively, you can consider using a functional type as a parameter or a type alias.

References and further reading:

This post is licensed under CC BY 4.0 by the author.