语法
中缀表达式
1
2
3
4// 声明
infix fun <A, B> A.to(that : B): Pair<A, B>
// 使用: A 中缀方法 B
1 to 2可变参数
1
2
3
4// varargs,类似于java的 ... ,但是位置没有限制
// 可以使用 * 来传入外部的变量作为可变参数的变量
val letters = arrayof("a", "b", "c")
printLetters(*letters)原生字符串
1
2
3
4val str = """
123
abc
"""判断
- 结构相等:== ,判断内容是否相等
- 引用相等:=== , 判断引用是否一样
区间
1
2
3
4
5// 区间[IntRange]
1 .. 10 // [1,...,10]
1 until 10 // [1,...,9)
10 downTo 1 // [10,9...1]
1 .. 10 step 2 // [1,3,5...]遍历
1
2
3
4// 遍历
for (i in array) {}
// 获取索引
for (i in array.indices) {}延迟初始化:
by lazy
1
2
3
4
5
6// 默认线程安全
val str by lazy { "str" }
// 并行模式
val str by lazy(LazyThreadSafetyMode.PUBLICATION) { "str" }
// 不做任何线程安全保证,也不会有任何线程开销
val str by lazy(LazyThreadSafetyMode.NONE) { "str" }- 变量必须是不可以变的:
val
- 在首次调用时才会初始化
lazy
属性会默认加入同步锁,在同一时刻只允许一个线程堆lazy属性进行初始化
- 变量必须是不可以变的:
函数
1
2
3
4// lambda 表达式
val foo = {x: Int, y: Int -> x + y} // foo.invoke(1, 2) 或 foo(1, 2)
// lambda 表达式函数体
fun foo(x: Int) = {y: Int -> x + y} // foo(1).invoke(2) 或 foo(1)(2)匿名内部类
1
2
3
4
5
6
7
8// lambda 表达式
val runnable = Runnable{}
// 匿名实现类
val runnable = object : Runnable {
override fun run() {}
}
// 或匿名内部类
executor.submit(object:Runnable{...})
密封类:
sealed
1
2
3sealed class State
class SuccessStatus:Status
class ErrorStatus:Status- 要继承必须将子类定义在同一个文件中
内联类
类似于包装类型,在编译时会把实际值替换到调用处
由于Kotlin
不能使用IntDef
模拟枚举的调用,可以考虑内联类来模拟枚举1
2
3
4
5
6inline class State(val ordinal:Int)
companion object {
// 模拟枚举
val Idle = State(0)
val Busy = State(1)
}可见性修饰符
修饰符 含义 与Java比较 public Kotlin
中默认修饰符,全局可见与Java中public效果相同 protected 受保护修饰符,类及子类可见 含义一致,作用域除了类和子类,包内也可见 private 私有修饰符,类内修饰只有本类可见,类外修饰文件内可见 私有修饰符,只有类内可见 internal 模块内可见 无 内部类和静态内部类
1
2
3
4class OutClass{
class StaticClass{} // 静态内部类
inner class InnerClass{} // 内部类
}委托代替接口实现
1
2
3
4
5
6
7
8interface CanFly {
fun fly()
}
open class Flyer : CanFly {
override fun fly() {
}
}
class Bird(flyer: Flyer) : CanFly by flyer解构
普通类想要使用结构方式可以手动写component1 component2一一对应的结构函数
1
2
3
4
5// 数据类最多支持五个参数的解构
val pair = Pair(1, 2)
val triple = Triple(1, 2, 3)
val (n1, n2) = pair
val (a, b, c) = triple伴生类
1
2
3
4
5class OutClass{
companion object { //相对于饿汉式静态内部类,全局只有一个实例
fun testFun() {}
}
}object
单例1
object Child
相当于
1
2
3
4
5
6
7
8public final class Child {
public static final Child INSTANCE;
private Child() {}
static {
INSTANCE = new Child();
}
}操作符
1
2
3
4
5
6var obj:TestData? = null
val result = obj?.value ?: -1 // 如果 obj 为空,则返回 1
val result = obj!!.value // 明确知道obj不为空
val stu: Student? = getStu() as Student // 强制转换,如果为空会报错
val stu: Student? = getStu() as? Student // 强制转换,如果 getStu 返回空,则转换为空泛型内联特化
1
2
3
4
5inline fun <reified T> method(t:T) {
val ts = Array<T>(3){}
val jclass = T::class.java
val list = ArrayList<T>()
}数组
1
2
3val a1 = arrayOf(o1, o2, o3) // 普通数组
val a2 = intArrayOf(1, 2, 3) // 基本数据类型数组:longArrayOf、floatArrayOf、doubleArrayOf....泛型多继承
1
2
3
4
5interface Ground
open class Fruit
class Water: Fruit(),Ground
fun <T> cut(t: T) where T : Fruit, T : Ground {}作用域操作符
- 如果需要返回自身的:apply{this} 或 also{it}
- 不需要返回自身的:run{this}或let{it}
- 满足条件才执行:
data.takeIf { it.age >= 18 }.let {...}
- 不满足条件才执行:
data.takeUnless { it.age >= 18 }.let {...}
with
和apply
1
2inline fun <T, R> with(receiver: T, block: T.() -> R): R
inline fun <T> T.apply(block: T.() -> Unit): T惰性求值:序列
1
2
3
4
5
6val list = listOf(1, 2, 3, 4, 5)
// 该操作会产生两个临时集合来记录元素,如果元素非常多时,就会有效率问题
list.filter {it > 2}.map {it * 2}
// 通过惰性求值减少临时集合的情况
list.asSequence().filter {it > 2}.map {it * 2}.toList()无限序列
1
2val naturalNumList = generateSequence(0) {it + 1}
naturalNumList.takeWhile {it <= 9}.toList()内联函数
内联函数能将函数内容编译到调用处,减少函数调用
1
2
3
4
5inline fun cost(block:() -> Unit)
// crossinline 禁止传递的block函数调用 r eturn 方法
inline fun cost(crossinline block:() -> Unit)
// noinline 该函数参数不做内联
inline fun cost(noinline block:() -> Unit)内联函数注意事项
- 由于JVM对普通函数有内联优化,所以普通函数比一定要采用内联函数,这样只会增加复杂性
- 尽量避免有大量函数体的函数进行内联,这样会增加字节码数量
- 内联函数无法使用闭包成员【闭包:内部函数持有外部函数变量】
运算符重载
参考:https://kotlinlang.org/docs/reference/operator-overloading.html
operator fun 类名.重载符号(一个参数):返回值 {}扩展函数
1
2
3
4
5class Person{...}
// 为Person类增加名为ext的扩展方法
fun Person.ext(s:Any) {
println(s)
}扩展属性
1
2val Data.extValue:boolean
get() = this.otherValue % 2 == 0静态扩展函数
1
2
3
4
5
6
7
8
9
10class Son {
companion object {
val age = 10
}
}
fun Son.Companion.foo() {
println("age = $age")
}
// 这样就可以不创建类的情况下直接调用
Son.foo()代理观察者
1
2
3
4
5
6
7class Data() {
var price: Int by Delegates.observable(0, { property, oldValue, newValue ->
// 当price的值变更时触发该函数
})
}
val data = Data()
data.price = 100代理限制
1
2
3
4
5
6
7
8class Data() {
var price: Int by Delegates.vetoable(0, { property, oldValue, newValue ->
newValue > 0
})
}
val data = Data()
data.price = 100
data.price = -100 // 该值不会设置成功原始方式创建协程
1
2
3
4
5
6
7
8
9
10suspend {
// coroutine heandle!
}.createCoroutine(object : Continuation<Unit> {
override val context: CoroutineContext
get() = Dispatchers.Default
override fun resumeWith(result: Result<Unit>) {
// Coroutine end!
}
}).resume(Unit)顶层协程
1
2val job = GlobalScope.launch {}
job.cancel()会阻塞当前线程直到协程作用域内的代码全部执行完
1
runBlocking {}
创建子协程,必须在协程作用域内使用
1
2val job = launch{}
job.cancel()挂起函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16// 没法使用launch函数
suspend fun name(){}
// 通过coroutineScope生成带协程作用域的挂起函数
suspend fun name()=coroutineScope{
launch{}
}
// 注意:coroutineScope也会阻塞当前协程,必须得里面的子协程执行完了才行
runBlocking {
coroutineScope {
launch {}
}
// 得等coroutineScope执行完了才会走到这
}
// 得等runBlocking执行完了才会走到这协程统一取消
1
2
3
4
5
6val job = Job()
val scope = CoroutineScope(job)
scope.launch{
// 协程域
}
job.cancel()超时协程
1
withTimeout(100){}
返回结果的协程域
1
2
3
4
5
6
7
8
9
10
11val r1 = async{
// 返回deferred时协程就已经开始跑了
}
val r2 = async{
// 返回deferred时协程就已经开始跑了
}
println("${r1.await()} - ${r2.await()}")// 阻塞返回结果
// async简化版
val result = withContext(Dispatchers.Dafault) {} // 阻塞返回结果,其中Dispatchers.Dafault为低并发策略suspendCoroutine
结合回调函数,需要在协程域和挂起函数中使用1
2
3
4
5
6
7
8suspend fun request(address:String):String {
return suspendCoroutine {continuation ->
new Thread({
continuation.resume(结果)// 成功
continuation.resumeWithException(结果)// 失败
}).start()
}
}同步代码块和同步代码函数
1
2
3
4
5
6
7fun method2() {
synchronized(this) {
}
}
fun method1() {
}volatile
1
private var count = 1
ReentrantLock
1
2val lock = ReentrantLock()
lock.withLock { method() }反射
首次使用会比java的慢
1
2Kotlin class:String::class String::class.java.kotlin
Java class: String::class.java注解变更java调用命名
1
2
3
4
5
6
7"name")//作用于文件名 (
"name")//作用于变量get函数 (
// 带默认参数函数适配java调用
//这样就会生成重载方法来适配默认参数
inernal // 声明的对象不想被java访问到,可以使用@JvmName("%abc")等特殊字符声明,这样java就被限制了