preface
Hello, everyone. Long time no see. It’s been nearly a decade since Kotlin was released. More and more developers are using Kotlin, especially Android developers, since Google officially announced Kotlin as a tier 1 developer language for Android at I/O 2017. Kotlin was announced as the first android development language at I/O 2019.
I started to learn Kotlin in the second half of 2018. At first, I bought a copy of “Kotlin from Zero to Master”, followed it and learned the basic grammar of Kotlin. Since the company was relatively small, there were not many Android developers, and there was a new project at that time. Therefore, I proposed to adopt Kotlin for the development of the whole project. Actually, it was quite risky at that time, because the project was in a rush, and the three Android developers were not good at Kotin, so I kept learning and writing during the development of the project. After the completion of the project, I felt that I had almost understood Kotlin (in fact, I only knew how to use it. Some parts of the project still use Java).
Later, I saw that more and more people were learning Kotlin in some developer forums, but I couldn’t understand a lot of things mentioned. The most excessive thing was that I had already written a project using Kotlin, and I didn’t know what the key words in Kotlin were for. I was really ashamed.
Before has been concerned about guo God’s blog, and android entry also see guo God’s “second line of code”. Later, I heard that the third Line of Code would be published, and it had Kotlin’s detailed explanation, so I immediately grabbed a signed copy of the book when it was released on the first day. The company let me go on a business trip before I came and had a good look at it. I haven’t had time to look at it until now. I didn’t use a lot of Kotlin’s good stuff. The Kotlin I used just turned Java code into Kotlin, which didn’t make any sense. Okay, here we go. Knock on the blackboard and underline!
Kotlin’s standard function
Standard functions in Kotlin refer to functions defined in standard.kt. Here are some Standard functions that I think are often used.
let
One of the main reasons we decided to use Kotlin in the first place was that it brought null-pointer exceptions to the language level, but it’s also a source of frustration for many developers like me.
Yes, Kotlin is not allowed to define it as empty for space safety, so you have to put a question mark on it, but… Many cases look like the following code:
For Kotlin’s space safety it is necessary to use question marks or two exclamation points to eliminate space safety errors. Just to eliminate space safety errors, it is not necessary in Java. It’s fine if we only use it once or twice, we use question marks or exclamation marks, but what about a bunch of calls? For example:
Parameter when how to do. Not to mention the speed of writing, bored to death…
And then… There was no need to write that! It could go like this:
var zhu:ZhuJ? = null
fun test(a){ zhu? .let { zhu-> zhu.name zhu.phone zhu.age zhu.sex } }Copy the code
Does the code suddenly feel much more elegant… The global variables are fine, and the method arguments are even better.
Guys, if I knew, I wouldn’t have to write a bunch of question marks and exclamation marks…
with
What this standard function does is that the code in the Lambda holds the context of the object, the last line of which is the return value.
It’s a little hard to understand, but here’s the code:
operator fun String.times(n: Int): String {
val sb = StringBuilder()
repeat(n){
sb.append(this)}return sb.toString()
}
Copy the code
This is an operator overload of the String class, which simply means repeating the String several times. As you can see, the StringBuilder object in this method is used several times, and often needs to be written once, but… If you use the with standard function…
operator fun String.times(n: Int): String {
return with(StringBuilder()) {
repeat(n) {
append(this@times)
}
toString()
}
}
Copy the code
Do you feel a little fresh, a lot of situations can be called like this.
run
This standard function is basically the same as with, except that the method is different. With requires an object to be written in parentheses to operate, while run is an object point to operate.
operator fun String.times(n: Int): String {
return StringBuilder().run {
repeat(n) {
append(this@times)
}
toString()
}
}
Copy the code
apply
The last line of apply is not used as a return value. The last line of apply is not used as a return value.
operator fun String.times(n: Int): String {
return StringBuilder().apply {
repeat(n) {
append(this@times)
}
}.toString()
}
Copy the code
The last line of both with and run returns a value, but apply does not.
The keyword
This piece needs a good summary of the next, really is, have written a project even the use of language keywords did not recognize the whole. One at a time!
lateinit
The lateinit keyword is used a lot. It is not necessary to set the question mark to nullable when defining a global variable as null. If you are sure it is not null, you can use lateInit, for example:
lateinit var zhuJ: ZhuJ
Copy the code
When you define a global variable like this you don’t have to set it to nullable, like in the Android project where we can be sure that the adapter is assigned and not empty, so we can use LateInit.
This should be noted that, even if we think it will not be empty, there will certainly be special cases that need to be judged. In this case, isInitialized should be used, and the method of use is as follows:
if (::zhuJ.isInitialized){
// Determine whether an assignment has been made
}
Copy the code
sealed
This keyword has not been used before, it is used to modify the class, meaning for the sealing class, before I have not understood the sealing class what to say, these two days have a good look, I understand the function is: can make the code more strict.
We usually define an interface, and then define a successful class and a failed class to implement the interface, and then judge:
class Success(val msg: String) : Result
class Fail(val error: Throwable) : Result
fun getResult(result: Result) = when (result) {
is Success -> result.msg
is Fail -> result.error.message
else -> throw IllegalArgumentException()
}
Copy the code
The above code is what we usually write, although there are only two cases, but you have to write else to check, if you don’t write otherwise the compilation will not pass. This is not the case with sealed classes:
sealed class Results
class Success(val mag: String) : Results()
class Failure(val error: Exception) : Results()
fun getMessage(result: Results) {
when (result) {
is Success -> {
println(result.mag)
}
is Failure -> {
println(result.error.toString())
}
}
}
Copy the code
Not only do you no longer have to write else, but kotlin checks to see if the condition includes all subclasses when making a when judgment. If not, kotlin will prompt you to add it, which greatly improves the robustness of the code and prevents undetected problems.
operator
This keyword is operator overloading, which is already used in the standard function above, where you can recustomize the operator to fulfill requirements that don’t work in the code, but actually work, and it’s also comfortable to use.
Here’s a look at the overloaded functions of our common operators: plus corresponds to plus, minus corresponds to minus, times corresponds to times, divisor corresponds to div, mod corresponds to REM, increment corresponds to inc, and decrement corresponds to dec.
Here’s how to use it:
operator fun String.times(n: Int): String {}
Copy the code
internal
This keyword can be used to modify classes and methods. It simply restricts access to different modules. If an internal method is defined in A Module, it can only be called in A Module, but not in B Module.
inner
This keyword is simple enough to modify a class, but… Can only be used to modify inner classes.
Let’s write a chestnut for you to know:
class Test {
var num: String? = null
class Zhu() {
var nums: String? = null
fun adds(a){ nums? .let { it.length } } } innerclass Jiang() {
var nums: String? = null
fun adds(a){ nums? .let { it.length } } } }Copy the code
The above code is very simple. It just defines a Test class, one of which is the Zhu class created directly internally, and the other is the Jiang class decorated with the inner keyword. Let’s just call it and see what the difference is:
Test().Jiang().nums
Test.Zhu().nums
Copy the code
If you want to use inner to modify the inner class, you need to obtain the instance of the Test class before you can use it, while the Zhu class directly created does not need to be used.
inline
This keyword stands for inline function and is easy to use by adding the inline keyword to a higher-order function. If you don’t know much about higher-order functions, I suggest you watch a video on throwline, which seems to be about Lanbda.
In a nutshell, higher-order functions are not as difficult as they seem. The name just sounds fancy. In a nutshell, passing in a method (which is essentially an object) as a method argument is a higher-order function. The principle of higher-order functions is to convert method arguments to interfaces and create anonymous inner classes to call, so each call to such a Lambda creates a new instance of the anonymous inner class and interface, causing additional overhead.
So that’s where inline comes in, it gets rid of that overhead, there’s nothing special about it, it just does the substitution, you just replace the method arguments where you call them to reduce the memory and performance overhead. Here’s how to use it:
inline fun high(block:(Int.Int) -> Int,block2:(Int.Int) - >Int){
block.invoke(5.6)
block2.invoke(4.5)}Copy the code
noinline
This keyword and the above inlined function keyword seems to be it! This is because if there are two or more method arguments in a higher-order function, the inline keyword will change all method arguments to inline functions. Why not replace them all? Since the function type arguments of an inline function are replaced at compile time, there are no real parameter types, but the function type arguments of a non-inline function can be passed freely to any other function, whereas the function type arguments of an inline function are only allowed to be passed to another inline function.
In order to explain why noinline exists, we can use it simply:
inline fun high(block:(Int.Int) -> Int.noinline block2:(Int.Int) - >Int){
block.invoke(5.6)
block2.invoke(4.5)}Copy the code
It is as simple as adding the noinline keyword before the method argument.
crossinline
Now that we’ve said noinline, we should also say crossnoinline. It lets methods that cannot use inline functions use inline functions.
Why are there functions that can’t use inline functions? Non-inline functions cannot return directly, but inline functions can, so an error is reported if another implementation of a Lambda or anonymous class is created or used in a higher-order function. Here’s another chestnut:
Runnable: Runnable: Runnable: Runnable: Runnable: Runnable: Runnable: Runnable That’s where the crossinline keyword comes in. It allows functions that can’t use inline functions to use inline functions:
Perfect solution! Crossinline is used to ensure that the return keyword is never used in Lambda expressions in inline functions, so there are no conflicts. The downside of this is that we can’t call a return from Runnable.
infix
This keyword is actually very useful, we can use it to do some very naughty operations:
val result = "zhujiang" * 3
val a = result begin "zhu"
Copy the code
Have you never seen this written before? Copying it to your computer will definitely give you an error. Infix’s main function is to define semantically comfortable ways to write things like result begin “zhu” above:
infix fun String.begin(prefix:String):Boolean = startsWith(prefix)
Copy the code
Is not very easy to use, is not already thought of a lot of SAO operation? Ha, ha, ha
But!
Note the following two points:
- Infix cannot be defined as a top-level function. It must be a member function of a class and can be defined into a class using extension methods
- The infix function must accept only one argument, and there is no limit to the type.
by
This keyword means delegate. Here’s how to use it:
class MySet<T>(val help:HashSet<T>) :Set<T> by help{
override fun isEmpty(a): Boolean {
return false}}Copy the code
You can create delegate classes for some classes and override them or add your own methods.
The generic
Generics are familiar, and we use them a lot in Java, such as List, HashMap<String,String>, and so on.
Generics in Kotlin
In fact, use the same as in Java, chestnut again:
class Generic <T>{
fun method(parem:T):T{
return parem
}
}
Copy the code
The above is used in class, of course can also be used in method:
fun <S> meth(parem:S):S{
return parem
}
Copy the code
The implementation of generics
Absolutely not in Java, and not practical, because Java’s generics erase mechanism…
But it’s possible in Kotlin, but… Conditional!
- Functions must be inline because only inline functions have substitution operations.
- A type must be declared with the reified keyword to indicate that the generic is to be implemented.
So, what does that do? Take a look at the code:
inline fun <reified T> startActivity(context:Context) {
context.startActivity(Intent(context,T::class.java))
}
Copy the code
Got it. Very convenient!
Contravariant and covariant generics
This… The next article will be devoted to contravariant and covariant generics. Owe first!
conclusion
In fact, there are many interesting things in Kotlin that we need to explore, such as coroutines. In fact, we used a lot of coroutines in the project, but we always feel that they are not used well enough, so we need to buckle them in time. Although the content is not much, but also wrote for a long time, the knowledge of the article is to follow Guo God’s “third line of code” to learn, also recommend you to buy, a book can learn a knowledge point is not loss, support legal, don’t download piracy to save dozens of dollars…
If this article has helped you, don’t forget the triple link. If there is anything inappropriate or wrong in the description of this article, please mention it, thank you very much. That’s it. I’ll see you later.