Kotlin standard functions:
Standard function let
fun main() {
val student = Student("lucky", 19);
study(student)
}
fun study(student: Student?) {
study?.doHomework()
study?.readBooks()
}
In the Kotlin learning - nullable system type , if the input parameter is nullable, it needs to be added every time the object function is called in the function ?.
, and the code writing is too cumbersome. At this time, you can combine ?.
operators and let
functions to optimize the code, as shown below:
fun main() {
val student = Student("lucky", 19);
study(student)
}
fun study(student: Student?) {
student?.let {
s ->
s.doHomework()
s.readBooks()
}
}
?.
The operator means to do nothing when the object is empty, and to call let
the function when the object is not empty. When I was doing lamda expression optimization before ( Kotlin learning - collection ): When there is only one parameter in the parameter list of the Lambda expression, it is not necessary to declare the parameter name, but the it keyword can be used instead, so the above code can be optimized Down:
fun main() {
val student = Student("lucky", 19);
study(student)
}
fun study(student: Student?) {
student?.let {
it.doHomework()
it.readBooks()
}
}
let
In addition to helping us simplify the non-null judgment, multi-threading can also control the null judgment of global variables.
var student: Student? = null
fun study() {
if (student !=null){
student.doHomework()
student.readBooks()
}
}
The above code will compile and report an error because the value of the global variable may be modified by other threads at any time. Even if the null judgment is performed, there is still no guarantee that the variable if
in the statement student
has no risk of null pointer. Use let
the function to modify:
var student: Student? = null
fun study() {
student?.let {
it.doHomework()
it.readBooks()
}
}
After the error disappears and it is judged that the variable is not empty, execute the statement in let. let can ensure that the variable is not empty student
during the execution of the lambda statement .student
Summary: let
It can help us simplify the non-null judgment, and it can also control the null judgment of global variables in multi-threading.
standard function with
fun main() {
val fruits = listOf("apple", "banana", "pear")
println(fruitPrint(fruits))
}
There is a list of fruits above, and the requirement is to splice them together in a fixed format. The usual implementation method is as follows:
fun fruitPrint(fruits: List<String>): String {
val fruitPrint = StringBuilder();
fruitPrint.append("My favorite fruits are : \n")
for (f in fruits) {
fruitPrint.append(f).append("\n")
}
fruitPrint.append("----- end -----")
return fruitPrint.toString()
}
//打印结果
My favorite fruits are :
apple
banana
pear
----- end -----
The object is called multiple times in a row where the string is spliced StringBuilder
. For this scenario, we can use with
functions to make the code more streamlined.
fun fruitPrint(fruits: List<String>): String {
return with(StringBuilder()) {
append("My favorite fruits are : \n")
for (f in fruits) {
append(f).append("\n")
}
append("----- end -----")
toString()
}
}
If with
an object is passed in as the first parameter of the function StringBuilder
, the context of the entire Lambda expression will be this StringBuilder
object. So we can directly call append()
and toString()
method in Lambda expression. The last line of code in the lambda expression is with
returned as the function's return value.
Summary: When frequent operations on the same object are required, with
functions can be used to simplify the code.
standard function run
run
The usage of functions with
is very similar to functions, but run
functions are usually not called directly, but are called on the basis of an object. And with
there are two input parameters, run
only one Lambda expression input parameter.
Likewise, the last line of code in the lambda expression of with
and is returned as the return value.run
The above example can be run
rewritten as a function:
fun fruitPrint(fruits: List<String>): String {
return StringBuilder().run {
append("My favorite fruits are : \n")
for (f in fruits) {
append(f).append("\n")
}
append("----- end -----")
toString()
}
}
standard function apply
apply
Functions run
are similar to functions, they must be called on an object, and only receive a Lambda parameter, and the context of the calling object will also be provided in the Lambda expression, but the apply function cannot specify the return value, but will automatically return the calling object itself.
fun fruitPrint(fruits: List<String>): String {
val sb = StringBuilder().apply {
append("My favorite fruits are : \n")
for (f in fruits) {
append(f).append("\n")
}
append("----- end -----")
}
return sb.toString()
}
Since apply
the function cannot specify the return value, it can only return the calling object itself, so it cannot be returned directly. Our return value declares the String type, so it needs to be converted.
Let's look at the usage in Android:
val intent = Intent(this,MainActivity::class.java).apply {
putExtra("data1","data1")
putExtra("data2",2)
putExtra("data3",true)
}
startActivity(intent)
When starting MainActivity, you can go to Intent
the parameters contained in the configuration.
standard function also
The usage of also is similar to that of apply, see an example:
fun studentInfoCheck(s: Student) {
s.also {
it.name = "Lucky" }
println(s.name)
}
Used internally it
to refer to the context, a series of operations can be performed on the object. The return value apply
can only return the calling object itself.
Differences in Standard Functions
Are you confused by learning here? Let’s compare the differences of the next few functions and it will look clearer.
standard function | internal context | return value |
---|---|---|
let | it | The last line of code in the let block |
with | this (can be omitted) | The last line of code in the let block |
run | this (can be omitted) | The last line of code in the let block |
apply | this (can be omitted) | call the object itself |
also | it | call the object itself |
The difference between with & run
From the above table, the internal context and return value with
of and run
are the same, so what is the difference between the two?
with
There are two input parameters,run
only one Lambda expression input parameter;- Air safety judgment methods are different;
For the second point, let's take a look at the case:
fun printStudentInfo() {
val s: Student? = null
with(s) {
this?.name = "Tom"
this?.age = 4
}
print(s)
}
The above is to use with
the empty judgment. When using it, you need to judge the non-empty again every time, change run
it to try
fun printStudentInfo() {
val s: Student? = null
s?.run {
name = "Tom"
age = 4
}
print(s)
}
First of all, run
the function call omits this
the reference, and the empty security check is carried out in the outer layer, and only when it is non-empty can it enter the function block to operate Student
. In comparison with
, run
functions are simpler, and null safety checks are less with
frequent.
Reference article
Differences between let, run, with, apply and also in Kotlin