Functional Interface in Kotlin

Functional Interface in Kotlin

What is Functional Interface or SAM (Single Abstract Method)?

Functional Interface which is also known as Single Abstract Method (or SAM) is just an interface with only one abstract method (method without implementation).

Representation

Functional interfaces can be defined by putting a fun modifier before the interface keyword and it should only have one abstract method.

Let’s directly jump into the example to understand the details:

// Normal Interface
interface ClickListener1 {
    fun onClick(view: View)
}

// Functional Interface or SAM (Single Abstract Method)
fun interface ClickListener2 {
    fun onClick(view: View)
}

class ClickUtil {

    private val view = View(null) //dummy view class just for the example

    private var clickListener1: ClickListener1? = null //normal interface
    private var clickListener2: ClickListener2? = null //functional interface
    private var clickListener3: ((View)->Unit)? = null //Higher order function

    fun setClickListener1(clickLis: ClickListener1) {
        clickListener1 = clickLis
    }

    fun setClickListener2(clickLis: ClickListener2) {
        clickListener2 = clickLis
    }

    fun setClickListener3(clickLis: (View)->Unit) {
        clickListener3 = clickLis
    }

    fun click1() {
        clickListener1?.onClick(view)
    }

    fun click2() {
        clickListener2?.onClick(view)
    }

    fun click3() {
        clickListener3?.invoke(view) //or clickListener(view), these are the only way to call the function
    }

}

fun main() {
    val clickUtil = ClickUtil()

    // In case of normal interface - Using anonymous object while passing to the function
    clickUtil.setClickListener1(object : ClickListener1 {
        override fun onClick(view: View) {
            // some click action
        }
    })

    // In case of Functional Interface - Using lambda while passing to the function
    clickUtil.setClickListener2 {view ->
        // some click action
    }

    // In case of Higher Order Function - Using lambda while passing to the function
    clickUtil.setClickListener3 {view ->
        // some click action
    }

}

In the above example, we have created basic example where we have three ways to represent basic clickListener:

  • Normal Interface — In first example, we have created normal interface (ClickListener1) with only one method (onClick()) and created the setClickListener1 function that take the object of ClickListener1 type. As ClickListener1 is an interface we need to use anonymous object while passing it.

  • Functional Interface — In second example, we have created functional interface (ClickListener2) with only one method (onClick()) and created the setClickListener2 function that take the object of ClickListener2 type. As ClickListener2 is an functional interface we can use lambda expression while passing it.

  • Function Type — In the third example, we directly used Kotlin Higher order function and use the lambda to pass the function.

Why Functional Interface?

  • It is clearly seen from example the reduction of boilerplate code when using functional interface, this makes code more concise and readable using lambda expression.

But main question is why not use Function types (Higher order function way) instead?

Advantage of using Functional interface over function types:

  • The function can be name differently that are being called (in our case onClick()), but in functional type it is always invoke().

  • Functional type can have only one member, while in case of functional interface we can add other non abstract methods as well. See below example:

/*
- Extending the above example, adding print statement (non abstract method)
- Extending the functionality of Functional interface.
*/
fun interface ClickListener2 {
    fun onClick(view: View)
    fun clicked() {
        println("Clicked")
    }
}

fun click2() {
    clickListener2?.onClick(view)
    clickListener2?.clicked()
}
  • Functional interfaces are optimized for primitive types as they have the advantage of not being wrapping types; that is, since a function type is a generic type at its core, primitives cannot be used with it. As a result, an input of type Int will be converted to Integer rather than int. For additional information about primitive type, see this blog.

Contact Me:

LinkedIn, Twitter

Happy Coding ✌️