This chapter focuses on collections, operator overloading, control flow operators, and so on.In addition to collections, you can think that other content is more complicated and difficult to use. I suggest that the reader practice more, or the brothers will not help you!
Kotlin mainstream collection framework
Frame analysis of sets
If you want to study the collection framework, you only need to open four files, as shown below:
The locations of these three files are:
/kotlin/Collections.kt
- This file mainly analyzes the inheritance relationship of collections
/kotlin/collections/Collections.kt
/kotlin/collections/Sets.kt
/kotlin/collections/Maps.kt
- These two files define the functions that create the set
Declaration of a collection
The file analysis for /kotlin/Collections.kt is as follows:
1. If you are careful, you will find that the biggest difference between this and java is that there will be one more interface and class with Mutable prefix before the original collection is added.For example, if you have a List interface, you will have an additional MutableList interface.MutableList represents the queue of modifiable elements, while List is the queue of elements that cannot be modified. This idea is mainly based on the collection of OC s.
2. Discarding the concept of Mutable mutability, let's talk about simple set categorization. Collections are divided into two main categories: Iterable interface (you can also say Collection class) and Map interface.
3. You can see the definition of Collection System:
- Iterable interface: Functions that primarily define an iteration queue
- Collection class: Maintains the queue primarily and determines if there is an element in the queue
- List class: Operations queue elements such as get, iterate through, and so on, but cannot operate on elements
- MutableList class: Has a List class and is able to add, modify, and delete elements
- Set/MutableSet: Similar to the concept of List and MutableeList.
4. Next, the definition of the Map system is introduced:
- Map: The corresponding map is a java map, which provides three collections (keys&values&entries), we can iterate through entries during the development process, and we cannot change the data inside the map.
- MutableMap: Additional operations to add/modify/delete elements.
List Creation
Next we will analyze the / kotlin/collections/collections.kt file:
- listOf(...) Create an immutable queue
- emptyList() creates an empty queue that returns a subclass of List called EmptyList
- mutableListOf() creates a variable queue
- null value elements cannot be inserted in queues created by listOfNotNull
For the EmptyList mentioned above, it is an empty queue, and if you visit an element in the queue, you will surely report an exception.The code is defined as follows:
internal object EmptyList : List<Nothing>, Serializable, RandomAccess {
private const val serialVersionUID: Long = -7390468764508069838L
override fun equals(other: Any?): Boolean = other is List<*> && other.isEmpty()
override fun hashCode(): Int = 1
override fun toString(): String = "[]"
override val size: Int get() = 0
override fun isEmpty(): Boolean = true
override fun contains(element: Nothing): Boolean = false
override fun containsAll(elements: Collection<Nothing>): Boolean = elements.isEmpty()
override fun get(index: Int): Nothing = throw IndexOutOfBoundsException("Empty list doesn't contain element at index $index.")
override fun indexOf(element: Nothing): Int = -1
override fun lastIndexOf(element: Nothing): Int = -1
override fun iterator(): Iterator<Nothing> = EmptyIterator
override fun listIterator(): ListIterator<Nothing> = EmptyIterator
override fun listIterator(index: Int): ListIterator<Nothing> {
if (index != 0) throw IndexOutOfBoundsException("Index: $index")
return EmptyIterator
}
override fun subList(fromIndex: Int, toIndex: Int): List<Nothing> {
if (fromIndex == 0 && toIndex == 0) return this
throw IndexOutOfBoundsException("fromIndex: $fromIndex, toIndex: $toIndex")
}
private fun readResolve(): Any = EmptyList
}
Set Creation
Next we will analyze the / kotlin/collections/Sets.kt file:
- emptySet() creates an empty set collection
- setOf(...) set collection create function
- mutableSetOf() variable set set set creation function
- LinkedSetOf() set chain list set function
- Set also has a subclass called EmptySet, which is an empty queue.
Map Creation
Unexpectedly, the blue part above is the map's creation function.The red part is the real definition of the function for the interface, if you know the operator of the extension class.
The Practice School of Collection
Error-prone point 1
You might think that List is a constant object, like the code below, and you think it will go wrong, but it won't.It simply makes mDatas refer back to a new queue.
var mDatas: List<Int> = emptyList()
mDatas = listOf(1,2,3)
Error-prone point 2
It is not allowed to modify the contents of an element to an immutable List. MutableList must be used instead, that is, if you feel that creating a queue requires modifying its contents, it must be a variable queue. If a queue does not change, try to use an immutable queue, which is more efficient.
var mDatas: List<Int> = listOf(1,2,3)
mDatas[2]=15
Modify as follows:
var mDatas: MutableList<Int> = mutableListOf(1,2,3)
mDatas[2]=15
The same is true for Maps, where element content cannot be changed by default.If you want to change the content of an element, you should use MutableMap.
var mDatas= mutableMapOf(
Pair("key1","value1"),
Pair("key2","value2"),
Pair("key3","value3")
)
mDatas["key1"]="newValue"
Error-prone point 3
Below I use an enhanced for loop to iterate through child elements, but remember to stop using the var/var keyword in for (), which is not allowed.
var mDatas: Set<Int> = setOf(1,2,3)
for(index :Int in mDatas){
Log.i("IT520",""+index)
}
If we want to traverse a map based on key-value pairs, then we need to declare two variables during the traversal process, and the code should do the following at this point:
var mDatas = mapOf(
Pair("key1","value1"),
Pair("key2","value2"),
Pair("key3","value3")
)
for((key,value) in mDatas){
Log.i("IT520","$key --- $value")
}
Error-prone point 4
For lists, you may want to get a control under an index, such as calling elementAt below, but if you pass in an index that cannot be found, an exception will be reported:
var mDatas = listOf(1, 2, 3, 4, 5)
Log.i("IT520",""+mDatas.elementAt(6))
Of course, if we want to find the first/last element of the first element, if we don't find it, we will report the exception directly as follows:
var mDatas2:List<Int> = emptyList()
//Log.i("IT520", "" + mDatas2.first())
Log.i("IT520", "" + mDatas2.last())
The above code is also easier to solve because the system also provides some alternative functions, such as elementAtOrElse (default if not found)/elementAtOrNull (null if not found)/firstOrNull/lastOrNull.
Kotlin Operator
Re-emphasize the code below to hit more
The following are the main descriptions of addition plus/subtraction/minus and negation not, coded as follows:
var a: Int = 3
a = a.plus(5)
Log.i("IT520"," $a ")
a = a.minus(2)
Log.i("IT520"," $a ")
var flag:Boolean =false
Log.i("IT520","${flag.not()}")
Sometimes we need to do self-increasing/self-decreasing, code as follows:
var a: Int = 3
a = a.inc() //A++ Inc for increase
Log.i("IT520", " $a ")
a = a.dec() //A--dec stands for decrease
Log.i("IT520"," $a ")
In addition to addition to addition and subtraction, there are multiplication, division and redundancy codes as follows:
//Multiplication times = Multiple
var c = a.times(b)
Log.i("IT520", "$c")
//Division divide = average
var d = a.div(b)
Log.i("IT520", "$d")
//Remainder rem/mod These two functions work the same if both divider and divider are positive
var e = a.rem(b)
Log.i("IT520", "$e")
If you want to determine if an element does not exist in a queue, java provides a contains method, and the in keyword can be used in kotlin with the following code:
var a = listOf(1, 2, 3, 4, 5)
//No 3 in a container returns Boolean
Log.i("IT520", "${3 !in a}")
This keyword can also be used to determine whether a substring exists in a string:
var str = "Hello world !"
Log.i("IT520", "${"Hello" in str}")
Control Flow Operators
The trinomial operator is a technique of comparison that we use, and its alternatives are described here:
Trinomial operators are cumbersome in Kotlin, but we can use the if statement instead:
var a: Int = 8
var b: Int = 6
//str = a>b ? "HHH" : "KKK"
var str = if (a > b) "HHH" else "KKK"
The most changed statement in the control process is the switch statement, which is now when:
var x = 3
when (x) {
1 -> Log.i("IT520","1")
2 -> Log.i("IT520","2")
else -> { // Notice this statement block
Log.i("IT520","else")
}
}
When there are multiple code statements inside a case, you can override them as follows:
var x = 3
when (x) {
1 -> {
Log.i("IT520","1")
Log.i("IT520","some code")
}
2 -> {
Log.i("IT520","2")
Log.i("IT520","some code")
}
else -> { // Notice this statement block
Log.i("IT520","else")
Log.i("IT520","some code")
}
}
If there are multiple conditions merging, you can do so:
var x = 1
when (x) {
0,1 -> Log.i("IT520","x == 0 or x == 1")
else -> Log.i("IT520","otherwise")
}
In fact, the case statement can also support a variety of conditions, he is not a simple Int type data, such as the following code, feel that:
var x = "Hello"
when (x) {
in "Hello Android !" -> Log.i("IT520","Hello Android ! contains Hello str")
else -> Log.i("IT520","otherwise")
}
If you want to determine a certain range of data, you can also say this:
var x = 3
when (x) {
in 1..10 -> Log.i("IT520","range 1 to 10")
else -> Log.i("IT520","otherwise")
}