A function that takes another function as an argument,

/** * higher order function * argument exists function */
fun num1AndNum2(num1: Int, num2: Int, operation: (Int.Int) - >Int): Int {
    return operation(num1, num2)
}

fun plus(num1: Int, num2: Int): Int {
    return num1 + num2
}

fun minusCustom(num1: Int, num2: Int): Int {
    return num1 - num2
}
Copy the code
  • use
private fun testHighFunction(a) {
        val num1 = 100
        val num2 = 80
        val result1 = num1AndNum2(num1, num2, ::plus)
        val result2 = num1AndNum2(num1, num2, ::minusCustom)
    }
Copy the code
  • Another way to customize the implementation of parameter functions
private fun testHighFunction(a) {
        val num1 = 100
        val num2 = 80
        
        // The first way
        val result1 = num1AndNum2(num1, num2, ::plus)
        val result2 = num1AndNum2(num1, num2, ::minusCustom)
        
        // The second way
        val result3 = num1AndNum2(num1, num2) { n1, n2 -> 
            n1 + n2
        }
        val result4 = num1AndNum2(num1, num2) { n1, n2 ->
            n1 - n2
        }
    }
Copy the code

Inline function

  • Because Kotlin’s higher-order functions rely on the power of the compiler to translate the higher-order function syntax into Java code. The interior is actually implemented through anonymous inner classes.
  • This way, we create a new anonymous inner class every time we call a higher-order function, which of course incurs a performance cost
  • To solve this problem, Kotlin provides inline functions. It completely eliminates the runtime overhead of using Lambda expressions
/** * higher order function * argument exists function */
inline fun num1AndNum2(num1: Int, num2: Int, operation: (Int.Int) - >Int): Int {
    return operation(num1, num2)
}

fun plus(num1: Int, num2: Int): Int {
    return num1 + num2
}

fun minusCustom(num1: Int, num2: Int): Int {
    return num1 - num2
}
Copy the code
  • This way, the Kotlin compiler will automatically replace the code in the inline function at compile time to where it was called, so there is no runtime overhead

Noinline, crossinline

  • What if there are multiple Lambda expressions in an inline function, but we just want to consolidate one of them? It’s easy, we can just use the noinline keyword
inline fun num1AndNum2(num1: Int, num2: Int, operation: (Int.Int) - >Int.noinline operation2: (Int.Int) - >Int): Int {
    return operation(num1, num2)
}
Copy the code
  • Why do you do that?
  • Because the code for an inline function makes a code substitution where it is called at compile time, it has no real parameter attributes.
  • The argument type of a non-inline function can be passed freely to any other function because it is a real argument, whereas the argument type of an inline function can only be passed to one other inline function, which is its biggest limitation.

The biggest difference between inline and non-inline functions

  • Inline functions can be returned using the return keyword
  • Non-inline functions can only return locally
  • So it is good programming practice to declare higher-order functions as inline functions

exceptions

  • This is because the inline function allows our referenced Lambda expression to return using the return keyword, but since we are calling the function type parameter in an anonymous function, it is not possible to return the outer function call at this point. Then you have a conflict.
  • So, in this case, we need to use the crossinline keyword
  • After using the Crossinline keyword, we cannot call the return keyword inside anonymous functions for function returns, but we can use the form return@runRunnable for function returns. Crossinline retains all the other features of inline functions, except for the use of the return keyword.
inline fun runRunnable(crossinline block: () -> Unit) {
    val runnable = Runnable {
        block()
    }
}
Copy the code