I. Introduction to Lambda

As mentioned above, it is widely used in Java, but it was only in Java8 that Lambda expressions were supported. In other programming languages (for example, Scala). Such expressions are one of the syntactic sugars. Thankfully, Kotlin has supported this syntax since open source came of age.

Lambda expressions are essentially anonymous functions because they are implemented in their underlying implementation. But we don’t have to worry about the underlying implementation when we use it. However, Lambda does reduce the amount of code to write, and also makes the code more concise. Lambda, the foundation of functional programming, is also fairly simple in its syntax. I’m going to give you an idea of the brevity of Lambda expressions with a simple code demo.

Ex. :

Mbtn.setonclicklistener (object: View.OnClickListener{override fun onClick(v: View?)) mbtn.setonClickListener (object: View. { Toast.makeText(this,"onClick",Toast.LENGTH_SHORT).show() } })Copy the code

Is equivalent to

// call mbtn.setonClickListener {toast.maketext (this,"onClick", toast.length_short).show()}Copy the code

Use of Lambda

As for the use of Lambda, I will explain from which aspect. First, I will introduce the characteristics of Lambda expressions, but explain from the syntax of Lambda.

2.1. Characteristics of Lambda expressions

The ancients cloud: want to take, first with it.

To learn Lambda expression syntax, you must first understand its characteristics. Here I summarize some characteristics of Lambda expressions. This will become clear when Lambda syntax and practices are explained below. That is:

  • LambdaExpressions are always enclosed in braces
  • Its argument (if present) is in->Previously declared (parameter types can be omitted)
  • Function body (if present) in->behind

2.2. Lambda syntax

To give you a thorough understanding of Lambda syntax, HERE are three uses. And I’ll give you an example

The syntax is as follows:

Val /var = {operation code} 2. Val /var Variable name: (parameter type, parameter type...) -> Return value type = {parameter 1, parameter 2... -> the code of the operation argument} can be equivalent to // written in such a way that the return value type of the expression is derived from the code of the operation. Val /var Variable name = {parameter 1: type, parameter 2: type,... Fun test(a: Int, parameter name: (parameter 1: type, parameter 2: type,...) -> Expression return type){... }Copy the code

Example explanation:

  • Case with no parameters

    Funtest (){println(" no arguments ")} // lambda code val test = {println(" no arguments ")} // Test () =Copy the code
  • In the case of parameters, here is a two-parameter example, just for demonstration purposes

    Fun test(a: Int, b: Int) : Int{return a + b} (Int, Int) -> Int = {a, b -> a + b} // or val test = {a: Int, b: Int -> a + b} //Copy the code
  • Lambda expressions as arguments in a function

    Fun test(a: Int, b: Int) : Int{return a + b} fun sum(num1: Int, num2: Int) : Int{return num1 + num2} // call test(10,sum(3,5)) Int) -> Int) : Int{return a + b.invoke(3,5)} // call test(10,{num1: Int, num2: Int -> num1 + num2}Copy the code

The implementation of this last one may be hard to understand, but please don’t be confused, you will read on, and it will be explained in the following practices and higher-order functions.

After the above examples and syntax introduction, we make a summary:

  1. lambdaExpressions are always enclosed in braces.
  2. Fully definedLambdaAn expression, like syntax 2 in the example above, has its full parameter type annotation, as well as the expression return value. In cases where we omit some type annotations, such as the other type of syntax 2 in the example above. When it concludes that the return value type is not ‘Unit’, its return value is->The type of the last (or only one) expression in the code following the symbol.
  3. In the example above, syntax 3 is expressed as:Higher-order functionswhenLambdaWhen an expression is used as a parameter, only the expression provides the parameter type and return type, so when we call this higher-order function, we need to set the parameter type toLambdaAn expression writes out its concrete implementation.
  1. invoke()Function: represents passThe function variablesCall itself because of the variable in the example abovebIs an anonymous function.

3. Lambda practice

Now that you know the syntax, you should be able to write and use lambda expressions in general, but the simple syntax is not enough to apply to complex situations in real projects. The following highlights Lambda practices from a few points.

3.1, it

  • itIs notKotlinA keyword (reserved word) in.
  • itIt’s in a function of higher orderLambdaCan be used if the expression has only one argumentitTo use this parameter.itCan be represented asThe implicit name of a single parameter, it isKotlinLanguage convention.

Case 1:

Val it: Int = 0 // that is, it is not a keyword in 'Kotlin'. Can be used for variable namesCopy the code

Example 2: The implicit name of a single parameter

// Here is an example of a higher-order function filter, which filters out values that do not meet the criteria. Val arr = arrayOf(1,3,5,7,9) // selects the first element in the array to be printed. The it here stands for each element. println(arr.filter { it < 5 }.component1())Copy the code

Example 2: This example is just for you to use it, filter higher-order functions, later Kotlin — Advanced (iv) : Set (Array, List, Set, Map) basic chapter will be explained in detail, there is no more introduction here. Let’s write a higher-order function for ourselves to explain IT. For the definition and use of higher-order functions, see This article in Kotlin’s Advanced part 2 of the From Nothing to Something series: Higher-order functions in detail.

Example 3:

 fun test(num1 : Int, bool : (Int) -> Boolean) : Int{
   return if (bool(num1)){ num1 } else 0
}

println(test(10,{it > 5}))
println(test(4,{it > 5}))
Copy the code

The output is:

10
0
Copy the code

In the higher-order test function, the return value is Int and the Lambda expression is conditional on num1 bits. Zero is returned if the Lambda expression is false and num1 is returned if the Lambda expression is false. So when num1 > 5, when the test function is called, num1 = 10 returns 10 and num1 = 4 returns 0.

3.2. Underline (_)

When Lambda expressions are used, an underscore (_) can be used to indicate unused arguments, indicating that the argument is not processed.

This is also useful when iterating through a Map collection.

For example:

val map = mapOf("key1" to "value1","key2" to "value2","key3" to "value3") map.forEach{ key , Value -> println("$key \t $value")}Copy the code

Output result:

key1     value1
key2     value2
key3     value3
value1
value2
value3
Copy the code

3.3 Anonymous Functions

  • Anonymous functions have the advantage of specifying their return value type explicitly.
  • It’s almost the same definition as a regular function. The difference is that anonymous functions have no function name.

Ex. :

Fun test(x: Int, y: Int) : Int{fun(x: Int, y: Int) : Int{fun(x: Int, y: Int) : IntCopy the code

Therefore, it can be abbreviated as the following.

Fun (x: Int, y: Int) : Int = x + yCopy the code

As you can see from the two examples above, anonymous functions differ from regular functions in that one has a function name and one does not.

Example exercise:

Val test1 = fun(x: Int, y: Int) = x + y Int = x + y val test3 = fun(x : Int , y : Int) : Int{return x + y} println(test1(3,5)) println(test2(4,6)) println(test3(5,7))Copy the code

The output is:

8 October 12Copy the code

From the above code, we can summarize several differences between anonymous functions and Lambda expressions:

  1. Parameter values of anonymous functions are always passed inside the parentheses. whileLambdaAn expression passes a value. There can be a shorthand that omits the parentheses.
  2. In a do not takeThe labelthereturnStatement, when an anonymous function returns the value of its own function, andLambdaThe return value of an expression is returned from the function that will contain it.

3.4. Numeric value of the function with the receiver

In Kotlin, the ability to invoke Lambda expressions is provided for the specified recipient object. In the body of a function literal, a method on the receiver object can be called without any additional qualifiers. It is similar to extension functions in that it allows you to access members of the receiver object within the function body.

  • Anonymous functions as receiver types

The anonymous function syntax allows you to specify the recipient type of the function literal directly, which is useful if you need to declare a variable using a function type with a receiver and use it later.

Ex. :

val iop = fun Int.( other : Int) : Int = this + other
println(2.iop(3))
Copy the code

The output is:

5
Copy the code
  • Lambda expressions as receiver types

The prerequisite for using a Lambda expression as the recipient type is that the recipient type can be inferred from the context.

Example: Here is an official example to illustrate

Class HTML {fun body() {... } } fun html(init: HTML.() -> Unit): HTML {val HTML = HTML() // creates the receiver object html.init() // passes the receiver object to the lambda return HTML} HTML {// The lambda with the receiver starts from this body() // Call a method of the receiver object}Copy the code

3.5 the closure

  • The so-calledclosure, that is, the function contains the function, where we can include (LambdaExpressions, anonymous functions, local functions, object expressions). We all know that functional programming is a good programming trend now and in the future. soKotlinIt also has this property.
  • As we all know,JavaClosures are not supported,JavaIs an object – oriented programming language, inJava,objectHe’s a first-class citizen.functionandvariableSecond-class citizens.
  • KotlinClosures are supported in,functionandvariableIt’s a first-class citizen, andobjectIt’s a second-class citizen.

Example: Look at a piece of Java code

Public class TestJava{private void test(){private void test(){// error, Private void test1(){} private void test1(){}Copy the code

Example: Look at a piece of Kotlin code

Fun test1(){fun test2(){// Correct, because Kotlin can nest functions}}Copy the code

Here’s how Kotlin’s closures are represented.

3.5.1 Carrying status

Example: Let a function return a function with a status value

fun test(b : Int): () -> Int{
    var a = 3
    return fun() : Int{
        a++
        return a + b
    }
}

val t = test(3)
println(t())
println(t())
println(t())
Copy the code

Output result:

7
8
9
Copy the code

3.5.2 Reference external variables and change their values

Ex. :

Var sum: Int = 0 val arr = arrayOf(1,3,5,7,9) arr. Filter {it < 7}. ForEach {sum += it} println(sum)Copy the code

Output result:

9
Copy the code

3.6 inAndroidThe developing ofRecyclerViewWrite one for the adapterItemClick on the event

class TestAdapter(val context : Context , val data: MutableList<String>) : RecyclerView.Adapter<TestAdapter.TestViewHolder>(){ private var mListener : ((Int , String) -> Unit)? = null override fun onBindViewHolder(holder: TestViewHolder? , position: Int) { ... holder? .itemView? .setOnClickListener { mListener? .invoke(position, data[position]) } } override fun onCreateViewHolder(parent: ViewGroup? , viewType: Int): TestViewHolder { return TestViewHolder(View.inflate(context,layoutId,parent)) } override fun getItemCount(): Int { return data.size } fun setOnItemClickListener(mListener : (position : Int, item : String) -> Unit){ this.mListener = mListener } inner class TestViewHolder(itemView : View) : Recyclerviewholder (itemView)} // Call TestAdapter(this,dataList).setonItemClickListener {position, item -> Toast.makeText(this,"$position \t $item",Toast.LENGTH_SHORT).show() }Copy the code