Kotlin quick start

Time:2022-6-11

1、 Kotlin Foundation

1. data type declaration

To define avariableVar keyword is required

//Defines a variable of type int that can be modified
var number = 39

If you want to define aconstantYou can use the Val keyword, which is equivalent to the Java final keyword

val name = "miku"

//Assigning a value to the constant defined by Val again will prompt an error
name = "ミク"

To declare a data type in kotlin, you must use VaR or Val to define it

2. data type

Kotlin data types are divided into basic data types and reference data types

Basic data types: Boolean, number, char

Reference type: nullable type, object, array type

The number type in kotlin generally refers to all types related to numbers, such as int, float, double and long

//java.lang.Integr  Int--->int
var intNumber:Number = 39

//java.lang.Float   Float--->float
var floatNumber:Number = 39.0f

//java.lang.Double   Double--->double
var doubleNumber:Number = 39.000000000000000

//java.lang.Long   Long--->long
var longNumber:Number = 39L

2.1. Kotlin predefined basic data types

var intType:Int = 39 //int

var shortType:Short = 39 //short

var byteType:Byte = 0 //byte

var boolType:Boolean = true //boolean

var stringType:String = "miku" //String

var floatType:Float = 39f //float

var doubleType:Double = 39.0000000000 //double

var longType:Long = 39L //long

var numberType:Number = 39 //Integr、Float、Double、Long

var charType:Char = '0' //char

String splicing, direct reference to variables through ${}, without the need for quotation marks + quotation marks

val name = "komine"
Val text = "before your private name, ${name}, you can apply for it."

print(text)

2.2. tuple

A tuple is a fixed length data structure that cannot be modified

//Second order tuple
var person1 = Pair("komin",16)

//Third order tuple
Var person2 = triple ("Komine", 18, "female")

Person2.first // the value of the first element
Person2.second // the value of the second element
Person2.third // the value of the third element

Kotlin’s tuple is actually the encapsulation of a generic object Generated by decompiling Class file shows that the second-order tuple is actually the corresponding pair class,

A third – order tuple is actually the corresponding triple class First, second and third correspond to getfirst(), getsecond(), and getthrid() methods respectively

If it is implemented in Java, it is almost like this. You can see that tuples are just a more convenient syntax provided by kotlin in in the source code phase

public class MyPair {

    private final First mFirstValue;
    private final Second mSecond;

    public MyPair(First first, Second second){
        this.mFirstValue = first;
        this.mSecond = second;
    }

    public First getFirst() {
        return mFirstValue;
    }

    public Second getSecond() {
        return mSecond;
    }
}

2.3. Nullable type

Kotlin defines a nullable data type. Only variables declared as nullable types can assign null to it All types declared by default are non – empty types

var str:String? =  Null // add "null" after the type? Indicates that the type can be empty

Print (STR?.length) // through Method to access member methods or variables of nullable types. If STR is null, subsequent calls will return null without error

//If you know clearly that STR is not empty at some time, you can pass!! Operate the variable, but if STR is null, a null pointer exception will be thrown
print(str!!.length)

2.4. array

Defining an array in kotlin is very simple Call arrayof() to create an array

var names = arrayOf("miku","rin","luka")
var numbers = arrayOf(16,14,17)

//Like Java, you can also access the elements of an array through the [subscript] method
print(names[0])

//Create an array with the specified length, and the value is null
var fixedArray = arrayOfNulls(39)

//Create an empty array
var emptyArray = emptyArray()

2.5. aggregate

Kotlin’s set is divided into variable set and immutable set Mutable sets all start with mutable

Variable set

//Mutablelist collection, which can contain the same elements
var mutableList = mutableListOf("miku","rin","luka")

//Key value pair, a set containing key and value
var mutableMap = mutableMapOf()
Var LinkedHashMap = linkedmapof() // equivalent mutablemap

//Mutableset collection. The same element will not appear in this collection. If the collection already contains a value, the addition operation will be ignored when adding
var mutableSet = mutableSetOf()
Var linkedset = linkedsetof() // equivalent mutableset

Immutable set

//List collection, unable to add
var list = listOf("miku","rin","luka")

//Map collection, unable to add
var map = mapOf(Pair("miku",16))
var linkedMap = 

//Set collection, unable to add
var set = setOf(0,1,2,3,4,5,6,7,8,9)

2.5.1 extension method

Tolist() returns an immutable list set

Tomap() returns an immutable map collection

Toset() returns an immutable set set

2.5.2 set operation

similar. LINQ query in net

Any determines whether there are elements that meet the conditions in the set

var mutableList = mutableListOf("miku","rin","luka")

val result:Boolean = mutableList.any(){
    It = = "Miku" // the value of one element is Miku
}

All determines whether all elements in the set meet the condition

var mutableList = mutableListOf("miku","rin","luka")

val result:Boolean = mutableList.all(){
    it. Isnotempty() // the length of the element is greater than 0
}

None determines whether all elements in the collection do not meet the conditions. If they meet the conditions, true is returned

var mutableList = mutableListOf("miku","rin","luka")

val result:Boolean = mutableList.none(){
    it. Isnotempty() // the length of the element is equal to 0 false
}

Count returns the number of elements that meet the conditions, similar to select count (*) from table where XX = XX in SQL

var mutableList = mutableListOf("miku","rin","luka")

val result: Int = mutableList.count {
    It = = "Miku" // returns the number of elements in the collection whose element value is Miku
}

Reduce accumulation from the first element to the last element

val numbers = mutableListOf(1,2,3,4,5,6,7,8,9)
val result: Int = numbers.reduce() {
    Sum: int, I - > sum + I //sum: declare a variable to receive the accumulation result i->: loop each element, sum + i: accumulate each element to sum
}

Reduceright accumulation from the last element to the first element

val numbers = mutableListOf(1,2,3,4,5,6,7,8,9)
val result: Int = numbers.reduceRight() {
    sum: Int, i -> sum + i
}

Fold is similar to reduce, but initialization can be set to accumulate from the initial value

val numbers = mutableListOf(1,2,3,4,5,6,7,8,9)
val result: Int = numbers.fold(10){
    sum, i -> sum + i
}

foldRight…

Sumof returns the sum of all elements in a collection. The elements of the collection must be of type number

val numbers = mutableListOf(1,2,3,4,5,6,7,8,9)
val result = numbers.sumOf{
    it
}

Dropwhile removes the elements that meet the conditions until they are not met, and returns the collection of the remaining elements

val numbers = mutableListOf(1,2,3,4,5,6,7,8,9)
val result = numbers.dropWhile {
    it < 5
}

Filter filters elements that do not meet the conditions and returns a new set of elements that meet the conditions

val numbers = mutableListOf(1,2,3,4,5,6,7,8,9)
val result = numbers.filter {
    it < 5
}

Filternot filters the elements that meet the conditions and returns a new set of elements that do not meet the conditions

val numbers = mutableListOf(1,2,3,4,5,6,7,8,9)
val result = numbers.filterNot {
    it < 5
}

Take returns n elements starting from the first element

val numbers = mutableListOf(1,2,3,4,5,6,7,8,9)
val result = numbers.take(5)   //{1,2,3,4,5}

Takelast returns n elements from the last element

TakeWhile returns the element that meets the given condition from the first element

val numbers = mutableListOf(1,2,3,4,5,6,7,8,9)
val result = numbers.takeWhile {
    it > 0
}

Drop returns the list after n elements are removed

val numbers = mutableListOf(1,2,3,4,5,6,7,8,9)
val result = numbers.drop(1)

Droplastwhile returns to start from the last element and remove the elements that meet the conditions

val numbers = mutableListOf(1,2,3,4,5,6,7,8,9)
val result = numbers.dropLastWhile {
    it > 5
}

Slice retains the element corresponding to the specified subscript

val numbers = mutableListOf(1,2,3,4,5,6,7,8,9)
val result = numbers.slice(listOf(1,2,3))

Map returns a new collection after transforming the elements in the collection through some method

val numbers = mutableListOf(1,2,3,4,5,6,7,8,9)
val result = numbers.map {
    val diff = 10
  
    it * diff
}

Subsequent updates

2.6. Type conversion

Kotlin converts one type to another through the as keyword

var numberType:Number = 39
var intType:Int = numberType as Int

Kotlin can automatically complete the boxing operation through the is keyword

open class GameConsole{

}

class PS4 : GameConsole() {

}

class NintendoSwitch : GameConsole() {
    public val version = "10.0"
}

fun main(args: Array) {
    val gameConsoles = arrayOf(PS4(),NintendoSwitch())
    val gameConsole = gameConsoles[1]

    //The boxing operation will be automatically completed, and the gameconsole will be recognized as a nitendoswitch within the current call range. You can directly access the members of the object without manual conversion
    if(gameConsole is NintendoSwitch){
        print(gameConsole.version)
    }
}

3. operator

Kotlin specific operators are = ===

3.1. Identity and non identity

Determine whether the addresses of two objects are equal

var obj1 = Object()
var obj2 = Object()

if(obj1 === obj2){
    Println ("identity")
}

if(obj1 !== obj2){
    Println ("non identical")
}

3.2. Bit operation

Only int and long types can be used

val i:Int = 10
val j:Int = 20

Val result = I SHL J // shift left signed
Result = I SHR J // shift right signed
Result = I ushr // unsigned shift right
Result = I and J // bitwise AND
Result = I or J // bitwise OR
Result = I XOR // bitwise XOR
Result = I inv J // negate by bit

3.3. Interval operator

Indicates whether a value is in a range or set

//i >=0 && i <= 100
if(i in 0..100){
    print(i)
}

Whether the array or collection contains a value

val names = arrayOf("miku","rin","luka")
if("miku" in names){
    Print ("include")
}

4. conditional statements

When is a conditional statement similar to switch in Java provided by kotlin It can do everything a switch can, and it also provides a more convenient syntax

fun test(i:Int){
    when(i){

        // case 1
        1 ->{

        }

	//case 2
        2 -> {

        }

 	//i >= 3 && i <= 9
        in 3..9 ->{

        }

	//default
        else ->{

        }
    }
}

When if no parameter is provided, it can also be used as if elseif

5. loop statement

It is not very different from the use of Java. Generally, it is easier to use it in combination with the interval operator in

val names = arrayOf("miku","rin","luka")
for (name in names){
    println(name)
}

//Traversing an array or collection with indexes
for ((index,name) in names.withIndex()){
  
}

val i = 0
for (i in 0..99){  //i = 0;i <= 99;i++
    println(i)
}

var i = 10
while (i > 0){
    println(i)
    i--
}

do {
    i--
    println(i)
}while (i > 0)

//foreach
val numbers = mutableListOf(1,2,3,4,5,6,7,8,9)
numbers.forEach{ it ->
    println(it)
}

//Foreach with index
val numbers = mutableListOf(1,2,3,4,5,6,7,8,9)
numbers.forEachIndexed{index, i ->  
    println("index[${index}] = $i")
}

6. functions

The function defined in kotlin uses the fun keyword If the method does not need the return value, it can not be written or unit can be written

fun sum(number1:Int,number2:Int):Int{
    return number1 + number2
}

6.1 default parameters

Kotlin adds support for default parameters. When a method specifies the default value of a parameter, the value of the parameter may not be provided when calling

To use the default parameter, add = after the parameter for assignment

fun sum(number1:Int,number2:Int = 0):Int{
    return number1 + number2
}

6.2 variable parameters

Like Java, kotlin also provides support for variable parameters, using the vararg keyword to declare variable parameters

fun sum(vararg number:Int){
    //Number is actually an array variable when used. You can call some array methods
}

6.3lambda expression

Lambda expression can be regarded as an anonymous function

var execute:(Int,Int) -> Int = {x,y ->
    x * y
}

println(execute(10,10))

If the function has only one parameter, it can be omitted and not written. This time, it is used to express it

var execute:(String) -> String = {
    it
}

println(execute("komine"))

6.4 higher order functions

Kotlin supports functions as parameters or return values. Functions containing such operations are called higher-order functions Use the double colon:: to pass a function as an argument

fun main(args: Array) {
   call(::method)
}

fun call(m:(number:Int) -> Int){
    println(m(39))
}

fun method(number:Int):Int{
    return number * number
}

You can also use a lambda expression to represent an anonymous parameter

call{number: Int -> [email protected] number * number }

Kotlin also provides some high-order functions for us to use, such as the apply function. In Android, initialization variables can be written in this way

var paint = Paint().apply {
    this.isAntiAlias = true
    this.color = Color.BLACK
    this.style = Paint.Style.STROKE
    this.strokeWidth = 10f
}

6.5 inline functions

Kotlin supports inline functions, which are the same as the inline functions of c++, because the execution of functions involves the steps of pressing the stack and exiting the stack, which will bring certain overhead

When a function is declared as an inline function, during compilation, the compiler will directly replace the function call with the content of the function body at all places where the function is called

Generally speaking, the nesting logic in inline functions should not be too complex. Whether to replace inline functions in c++ is determined by the compiler. Kotlin will directly replace them according to the inline key

It can be seen from the class file generated by decompiling that inline function is to directly replace the place where there is a function call with the content of the function body

fun main(args: Array) {
    test()
}

inline fun test(){
    for (i in 0..99){
        println(i)
    }
    for (i in 0..99){
        println(i)
    }
    for (i in 0..99){
        println(i)
    }
    for (i in 0..99){
        println(i)
    }
    for (i in 0..99){
        println(i)
    }
    for (i in 0..99){
        println(i)
    }
}

Decompile results

If a function parameter type or lambda expression is included in a function parameter, you can also use the noinline keyword to specify a function without parameter inlining

Crossinline keyword to be added

2、 Kotlin advanced

1. coordination process

A coroutine is a product of running on a thread. It has its own stack memory and local variables, and is called a lightweight thread Its internal implementation is accomplished by the compiler

Official documentation

Before using a collaboration, you need to add dependencies

implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.1'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.1'

Simple usage

GlobalScope.launch(context = Dispatchers.Default, start = CoroutineStart.DEFAULT) {
    //Delay 1.5 seconds
    delay(1500L)
    Println ("current thread:" + thread. Currentthread() name)
    println("World")
}
println("Hello,")
Println ("current thread:" + thread. Currentthread() name)
Thread.sleep(3000L)

Context: the context of the coroutinedispatch process. The thread scheduler for coroutinedispatch process running is set here. It has four thread modes:

Dispatchers. Default / / default

Dispatchers. IO / / working on other threads

Dispatchers. Main / / main thread

Dispatchers. Unconfined / / not specified is the current thread, kotlinx coroutines. DefaultExecutor

You can also create a collaboration context, which can also be understood as the thread on which the collaboration runs

val context = newSingleThreadContext("single")

Start: startup mode. The default is coroutinestart Default: it will be started after creation

CoroutineStart.DEFAULT

CoroutineStart.ATOMIC

CoroutineStart.UNDISPATCHED

CoroutineStart. Lazy lazy loading mode, it will return a job object, you can manually open it

val job = GlobalScope.launch(context = Dispatchers.Default, start = CoroutineStart.LAZY) {
    //Delay 1 second
    delay(1500L)
    Println ("current thread:" + thread. Currentthread() name)
    println("World")
}
println("Hello,")
Println ("current thread:" + thread. Currentthread() name)

job.start()

Thread.sleep(3000L)

GlobalScope. Async with return value

suspend fun main(args: Array) {
    val result = GlobalScope.async {
        delay(1000L)
        [email protected] "async"
    }

    println(result.await())
    Thread.sleep(3000)
}

Async will block the current coroutine and wait for the current coroutine to be executed. The function calling await() needs to be decorated with the suspend keyword

Suspend indicates that the current process is suspended

fun main(args: Array) {
    GlobalScope.launch {
        //The get method is decorated with suspend, which means that the current workflow will be suspended when called
        val str = get()
        //Will wait for get() to complete before continuing
        printStr(str)
    }
    //Prevent process from ending
    Thread.sleep(3000L)
}

suspend fun get():String{
    Println ("get() is executing..")
    delay(1000)

    return "data"
}

suspend fun printStr(str:String){
    println(str)
}

Coprocesses can also be nested. Calling await will block external coprocesses, and the code will still run in sequence

fun main(args: Array) {
    GlobalScope.launch {
        val str = GlobalScope.async {
            [email protected] get()
        }.await()

        GlobalScope.launch{
	    printStr(str)
        }
    }
    //Prevent process from ending
    Thread.sleep(3000L)
}

suspend fun get():String{
    Println ("get() is executing..")
    delay(1000)

    return "data"
}

suspend fun printStr(str:String){
    println(str)
}

To be added

2. object oriented

2.1 declaration of class

Like many languages, kotlin uses the class keyword to declare a class

class Person{

}

2.1.1 internal class

class Person{
    //The declaration of the inner class is decorated with the inner keyword
    inner class Info{
  
    }
}

To instance an internal class, you need to instantiate the main class first

val person = Person("miku")
val info = person.Info()

2.1.2 data class

A class modified by data class is called a data class. A data class must provide a constructor with parameters Data classes generally do not define methods

data class MyData(val height:Float,val weight:Float,val money:Float){

}

2.1.3 enumeration class

It is basically the same as the enumeration class in Java

enum class DirectionEnum{
    East{
        override fun move() {

            //Name: name of current enumeration constant
            //Ordinal: the value of the current enumeration constant
	    println("name$name")
            println("value:$ordinal")
        }
    },
    South{
        override fun move() {

        }
    },
    West{
        override fun move() {

        }
    },
    North{
        override fun move() {
  
        }
    };
    abstract fun move();
}

2.1.4 sealing

emm… I don’t know how to use it. I’ll add later

2.1.5 abstract classes

Declare an abstract class using the abstract keyword

open abstract class Person(name:String, age:Int){
  
}

2.2 constructor

Kotlin’s constructor can be written directly after the class name, which is called the main constructor. The constructor defined in this way has no method body and needs to perform initialization

You can use init code blocks

open class Person(name:String, age:Int){

    init {
        Println ("main constructor execution...)
        println("name:${name},age = $age")
    }
}

2.2.1 secondary constructor

The constructor defined through the constructor is called a secondary constructor, and the primary constructor needs to be called indirectly for initialization

fun main(args: Array) {
    val person = Person("miku")
}

open class Person(name:String, age:Int){

    init {
        Println ("main constructor execution...)
        println("name:${name},age = $age")
    }

    //The secondary constructor needs to call the primary constructor indirectly through the this keyword
    constructor(name:String) : this(name,16) {
        Println ("sub constructor execution...)
    }
}

2.2.2 constructor privatization

If you do not want to access the constructor of the class outside the class, you can use theprivate constructorTo decorate the primary constructor

class ListDialogprivate constructor(context: Context) :Dialog(context) {

}

2.3 succession

If you want a class to be inherited by other classes, you need to add the open keyword before the class declaration and use the colon to inherit

open class Person{
    open fun sodayo(){}
}

class Student : Person() {

}

If the subclass wants to override the method defined by the parent class, the method must be modified by the open keyword, and the modifier of the abstract method is open by default

2.4 static members

Kotlin does not provide the static keyword. If you want to implement static member calls like Java, you can use the company object code block to define static members

It is called companion object in kotlin, and the static member is replaced by the member of companion object

class PS4{
    companion object{
        val FIRMWARE_VERSION:Float = 10.0f
        fun boot(){
            println("boot...")
        }
    }
}

Just like Java, then call static members by class name

PS4.boot()
PS4.FIRMWARE_VERSION

2.5 interface

Use interface to declare an interface Same usage as Java

interface Callback{
    fun onSuccess()
    fun onFailed()
}

3. generics

Basically consistent with Java

class Data(private val data:T){
    fun get():T{
        return data
    }
}
val data1 = Data("String")
println(data1.get())

val data2 = Data(16)
println(data2.get())

3.1out and in keywords

Out and in are used in kotlin instead of “out”? Extensions and? Super is used. The specific usage is similar to Java

fun main(){
    val ps4List = mutableListOf()

    setGameConsoles(ps4List)
  
    val gameConsoles = getGameConsoles()
    for (gameConsole in gameConsoles){
        val ps4 = gameConsole as PS4
        ps4.play()
    }
}

// out ----> ? extends GamesConsole
fun setGameConsoles(gamConsoles:MutableList){
   
}

//in -----> ? super PS4
fun getGameConsoles():MutableList{
    val gameConsoles = mutableListOf()
    gameConsoles.add(PS4())
    gameConsoles.add(PS4())
    return gameConsoles
}

open class GameConsole{
    open fun play(){

    }
}

class PS4 : GameConsole(){
    override fun play() {
        println("ps4 play...")
    }
}

class NintendoSwitch : GameConsole(){
    override fun play() {
        println("ns play...")
    }
}

4. entrustment

In fact, it is the agent design pattern

4.1 usage scenarios of delegation

Implementation of proxy pattern in Java

//Payment interface
public interface IPay {
    void pay();
}

//Alipay payment
public class AliPay implements IPay{
    private float mMoney;
    public AliPay(float money){
        mMoney = money;
    }

    @Override
    public void pay() {
        Log. D ("Alipay", "Alipay payment" + mmoney + "Yuan...");
    }
}

//Wechat payment
public class WeChatPay implements IPay{
    private float mMoney;
    public WeChatPay(float money){
        mMoney = money;
    }

    @Override
    public void pay() {
        Log. D ("wechatpay", "wechat payment" + mmoney + "Yuan...");
    }
}

//Proxy object
public class ProxyPay implements IPay{
    private IPay mPay;
    public ProxyPay(IPay pay){
        mPay = pay;
    }

    @Override
    public void pay() {
        mPay.pay();
    }
}

Implementation of kotlin’s proxy pattern

interface IPay{
    fun pay()
}

class Alipay(private val money:Float) :IPay{
    override fun pay() {
        Println ("Alipay pays $money...)
    }
}

class WeChatPay(private val money: Float) :IPay{
    override fun pay() {
        Println ("wechat payment $money...)
    }
}

class PayDelegate(private val play:IPay) :IPay by play{
    //Nothing needs to be done. The system helps us complete a series of operations
}

It can be seen that kotlin’s delegation actually simplifies the implementation process of the proxy mode

4.2 attribute delegation

Delegate the assignment of attributes to other classes Other classes can be used to uniformly control the value and legitimacy of attributes

Basic use

//To declare an interface, it is not necessary that the interface can also be a class
interface IPropertyDelegate

class PS4 :IPropertyDelegate{
    var version:String by DataDelegate()
}

class NintendoSwitch :IPropertyDelegate{
    var version:String by DataDelegate()
}

class DataDelegate {
    private var version:String = ""
    operator fun setValue(thisRef: IPropertyDelegate, property: KProperty, value: String) {
        this.version = value
    }

    operator fun getValue(thisRef: IPropertyDelegate, property: KProperty): String {
        return this.version
    }
}

When assigning a value to the version of PS4 or nintendoswitch object, you will go to the setValue () method of datadelegate object to achieve the operation of unified assignment. The same operation does not need to be written once in each class

val ps4 = PS4()

ps4.version = "7.55"
println(ps4.version)

val ns = NintendoSwitch()

ns.version = "13.0"
println(ns.version)

5. others

5.1 extension function

Adding an extension function to a class has the same effect as calling a member function It is generally defined in a unified file. You don’t need to define a type first. Just write it directly

//Extended a first method to string
fun String.first():Char{
    return this[0]
}

println("komine".first())

5.1 extended attributes

Add an extended property to a class

val Int.dp:Int
    get(){
        //Let's make a simple simulation. This is not the case in development
        return this * 1.5f.toInt()
    }

For example, add a DP extension attribute to the int type to convert the int value to the corresponding DP

val width = 39.dp

To be updated