【Kotlin】 基础语法篇

记录些容易遗忘或易混淆的语法结构和关键字

关键字

val只读的变量
var可读可写的变量
const val 编译时常量,只能修饰基本数据类型,只能在函数外定义,因为是编译时初始化的。
vararg函数的变长参数
$用于字符串模板中变量名或变量值
is类型检测
in区间判断
inner 修饰内部类,内部类可以用this@Class来获取外部类对象,外部类通过对象调用内部类方法,不用inner修饰的类但写在内部称为嵌套类,外部类通过静态调用获取嵌套类对象,嵌套类不可通过this获取外部类对象
internal同模块内可见
inline内联函数修饰符,用于提升运行速度,使得方法压栈的方式变成替换代码直接执行,从而提高效率
sealed 修饰密封类,类似于枚举,结合when条件语句使用,可列举出类的所以情况而不写else,这点比普通的switch要强,便于拓展时不遗漏新的属性
object对象声明,可方便地实现对象单例
companion object 伴生对象,静态调用
by委托,代理模式的快速实现,可实现类委托(委托的接口方法实现,无需重复写模板代码),属性委托(委托的get,set方法),可委托给lazy{}Delegates.observablemap,其中by lazy提供三种现场模式:LazyThreadSafetyMode.SYNCHRONIZED 加入线程锁实现线程安全(默认模式,此模式在单例模式实现中使用方便)、LazyThreadSafetyMode.NONE 无线程安全,占资源少 、LazyThreadSafetyMode.PUBLICATION 无线程安全但取第一个线程计算的值为准。其中by Delegates.observable快速实现对某个对象的观察,当值发生改变时触发回调
operator 识别属性委托的关键字

//属性委托类的写法
class StringDelegate(private var s: String = "Hello") {
operator fun getValue(thisRef: Owner, property: KProperty<*>): String {
return s
}
operator fun setValue(thisRef: Owner, property: KProperty<*>, value: String) {
s = value
}
}

lateinit 修饰变量,代表这个变量使用前一定会赋值,编辑器不必判空

使用于明确在某一位置的初始化情况,同时该属性需是var可变类型;如果可以是任意位置则by lazy更合适

in 0..10 range表达式 代表值在某个范围内,返回类型为boolean
when 表达式 ,类比JAVA的switch,但比switch 功能更加多样
Unit 空类型,类比Java的void
Any 基础类,类比java 的Object
takeIf 判断真假,代替if(true){}语句,比如 a?.takeIf(isPlaying)?.apply{//}
${} 字符串模版,括号中可以写入变量,表达式等,与java不同的是,kotlin中when,if 是表达式,java中if,switch是语句
` ` 反引号,作用一:可替代方法名;作用二:使关键字变成普通的字符串
T::class.java 获取泛型class
JvmField 属性注解,消除属性的get,set方法,默认情况下私有属性会有公有的get方法,加上注解后消除get,set方法,默认属性是公有
JvmStatic注解属性时,属性变成静态,生成静态get,set方法,作用方法时,方法变成静态

单例写法

可以直接使用object对类修饰实现单例,推荐以下写法使用时创建对象,并考虑多线程的创建问题

class SingleC {
    companion object {
        val sIntance by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
            SingleC()
        }
    }
}

匿名函数

顾名思义,匿名函数不显示方法名,但函数的参数必须写在括号内,无参可省略括号

内联函数

函数特点使用
letit代指,强调作用域,返回最后一行或空,判null方便obj?.let{it.todo}
withthis代指可缺省,返回值为最后一行或returnwith(user){todo}
runthis代指可缺省,返回值同with,判空方便obj?.run{todo}
applythis代指可缺省,返回对象本身,适用初始化obj?.apply{todo}
alsoit代指,返回对象本身,适用链式调用obj?.also{todo}

集合

  1. 集合排序

val numbers = mutableListOf(1, 2, 3, 4) //可变列表
//随机排列元素
numbers.shuffle()
println(numbers)
numbers.sort()//排序,从小打到
numbers.sortDescending()//从大到小
println(numbers)
//定义一个Person类,有name 和 age 两属性
data class Language(var name: String, var score: Int)
val languageList: MutableList = mutableListOf()
languageList.add(Language(“Java”, 80))
languageList.add(Language(“Kotlin”, 90))
languageList.add(Language(“Dart”, 99))
languageList.add(Language(“C”, 80))
//使用sortBy进行排序,适合单条件排序
languageList.sortBy { it.score }
println(languageList)
//使用sortWith进行排序,适合多条件排序
languageList.sortWith(compareBy(
{ it.score }, { it.name })
)

println(languageList)

注意事项

  1. 方法入参是常量,不可修改
class Main {
/**
* Kotlin 入参是常量
*/
fun print(a: Int = 1, b: String = "") {
// a = 10; // 错误:Val cannot be reassigned!!!
}
}
  1. as的判定写法
//正确写法,转换失败自动转换为空对象
var strAble = text as? String
//错误写法2,text不是String时,同样会报异常
var strAble2 = text as String?
  1. 构建常量类@file:JvmName("Constant")放于包声明前面

协程

一个进程有多个线程,一个线程有多个协程,又称之为微线程,kotlin中默认实现了很多协程作用域,即各种各样的scope,可以用写同步代码的方式来书写异步代码

协程库支持

dependencies {
    // Kotlin
    implementation "org.jetbrains.kotlin:kotlin-stdlib:1.4.32"

    // 协程核心库
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.3"
    // 协程Android支持库
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.3"
    // 协程Java8支持库
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.4.3"

    // lifecycle对于协程的扩展封装
    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
    implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.2.0"
    implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0"
}

suspend挂起函数,在协程内部使用,耗时任务会将协程挂起,直到任务完成,与阻塞不同点1.阻塞的进程依旧在内存中,挂起的进程被交换到内存外;2.阻塞一般是等待资源,挂起一般是用户或系统的需要3.阻塞在有资源后激活,挂起在用户主动激活

有个形象的比喻

挂起线程的意思就是你对主动对雇工说:“你睡觉去吧,用着你的时候我主动去叫你,然后接着干活”。
使线程睡眠的意思就是你主动对雇工说:“你睡觉去吧,某时某刻过来报到,然后接着干活”。
线程阻塞的意思就是,你突然发现,你的雇工不知道在什么时候没经过你允许,自己睡觉了,但是你不能怪雇工,因为本来你让雇工扫地,结果扫帚被偷了或被邻居家借去了,你又没让雇工继续干别的活,他就只好睡觉了。至于扫帚回来后,雇工会不会知道,会不会继续干活,你不用担心,雇工一旦发现扫帚回来了,他就会自己去干活的。

launch创建一个协程,接受三个参数:

  1. CoroutineContext上下文,代表运行在哪种线程中,有四种模式Dispatchers.Default,
    Dispatchers.IO:挂起时运行在默认线程池,挂起恢复后运行在IO线程
    Dispatchers.Main:运行在主线程,但主线程后面的代码会先执行,挂起恢复后也在主线程
    Dispatchers.Unconfined:挂起恢复后在默认线程池中
    也可以自己指定在自定义的线程池中运行;
  2. CoroutineStart启动模式,DEAFAULT,ATOMIC,UNDISPATCHED,LAZY(需手动启动)
  3. block闭包方法,传入要执行的操作
    async创建个带返回值得协程,返回值是Deferred,继承自Job,新增await方法接受返回值,等待过程中会挂起协程,有结果后恢复协程

launch 和 async 是常用的两种创建协程的方式,一般使用async时是期望有返回值的,在await中获取,由于await是挂起函数,所以await的请求是在协程中,应用情况一般是在一个协程内部需开启另一条协程去获取数据,下面数据继续进行,到await时候等待数据回来

mScope.launch {
        // 开启一个IO模式的线程 并返回一个Deferred,Deferred可以用来获取返回值
        // 代码执行到此处时会新开一个协程 然后去执行协程体  父协程的代码会接着往下走
        val deferred = async(Dispatchers.IO) {
            // 模拟耗时
            delay(2000)
            // 返回一个值
            "Quyunshuo"
        }
        // 等待async执行完成获取返回值 此处并不会阻塞线程  而是挂起 将线程的执行权交出去
        // 等到async的协程体执行完毕后  会恢复协程继续往下执行
        val date = deferred.await()
    }

withContext不创建新的协程,在指定协程上运行

val job2 = mScope.launch(Dispatchers.IO) {
            // 此处是IO线程模式
            // 切线程 将协程所处的线程环境切至指定的调度模式Main
            withContext(Dispatchers.Main) {
                // 现在这里就是Main线程了  可以在此进行UI操作了
            }
        }

runBlocking 独立使用,delay会阻塞线程,主要用于交接阻塞式与挂起的非阻塞式协同运行的场景
job构建协程得到的对象,可执行start()–开始,join()–等待执行完毕,cancel()–取消,cancelAndJoin()–等待协程执行完毕再取消

理解协程的运行流程,由于多个协程是运行在一个线程中,正常谁写前面谁先运行,运行完后运行下一个,运行过程中如果被挂起,则让出线程运行下一个,挂起恢复后等正在运行的协程运行完运行该协程

协程类型
GlobalScope 作用于整个应用程序,适用于执行长期运行的异步任务,比如网络请求或者定时任务
MainScope 指定了Dispatchers.Main作为其默认协程调度器,通常用于与UI相关的协程操作,生命周期通常是Activity或Fragment的生命周期
lifecycleScope 生命周期与LifecycleOwner一致,一般是启动activity时执行异步操作使用

Flow

Flow使用

参考

协程三部曲
一文了解协程
kotlin实战

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值