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:
Lambda
Expressions 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:
lambda
Expressions are always enclosed in braces.- Fully defined
Lambda
An 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.- In the example above, syntax 3 is expressed as:
Higher-order functions
whenLambda
When 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 toLambda
An expression writes out its concrete implementation.
invoke()
Function: represents passThe function variables
Call itself because of the variable in the example aboveb
Is 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
it
Is notKotlin
A keyword (reserved word) in.it
It’s in a function of higher orderLambda
Can be used if the expression has only one argumentit
To use this parameter.it
Can be represented asThe implicit name of a single parameter, it isKotlin
Language 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:
- Parameter values of anonymous functions are always passed inside the parentheses. while
Lambda
An expression passes a value. There can be a shorthand that omits the parentheses.- In a do not take
The label
thereturn
Statement, when an anonymous function returns the value of its own function, andLambda
The 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-called
closure
, that is, the function contains the function, where we can include (Lambda
Expressions, anonymous functions, local functions, object expressions). We all know that functional programming is a good programming trend now and in the future. soKotlin
It also has this property.- As we all know,
Java
Closures are not supported,Java
Is an object – oriented programming language, inJava
,object
He’s a first-class citizen.function
andvariable
Second-class citizens.Kotlin
Closures are supported in,function
andvariable
It’s a first-class citizen, andobject
It’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 inAndroid
The developing ofRecyclerView
Write one for the adapterItem
Click 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