目录
Kotlin的跨平台特性
Java跨平台的实现是通过JVM生成二进制字节码并且,并通过各个平台特质的JVM运行,而Kotlin 可以编译成 Jvm 字节码运行在 Java 虚拟机上,也可以编译成 JavaScript 运行在浏览器、Node 等 JavaScript 环境中,甚至可以编译成机器码,直接运行在机器本地环境中
声明变量和内置数据类型
var 和 val :
var是可变变量(可读可写),val是可读变量(只能读)
声明变量格式:
var/val 变量名 [:数据类型] = 值
注:(有初始值时,中括号中可省略,kotlin会进行类型推导)
数据类型
getter和setter
Kotlin中getter 和 setter 都是可选,只需控制变量修饰符,比如:
val不允许设置setter函数,因为它是只读的。
循环语句
Kotlin有两种循环方式,while和for-in,while与java中的while没有区别,for-in是对Java for-each的加强,Kotlin舍弃了for-i的写法,for-in需借助区间来使用
其中
- unitl关键字实现左闭右开
- step关键字实现跳步
- downTo关键字实现降序循环
Lambda表达式(匿名函数)
定义时不取名字的函数,匿名函数通常整体传递给其他函数,或者从其他函数返回,对kotlin很重要,有了它就可以根据需要制定特殊规则,轻松定制标准库里的内置函数
fun main() {
val totalS = "Mississippi".count { letter -> letter == 's' }
println(totalS)
}
函数类型和隐式返回
kotlin中匿名函数也有类型,匿名函数可以当做变量赋值给函数类型变量,就像其他变量一样,匿名函数就可以在代码里传递了,变量有类型,变量可以等于函数,函数也会有类型,函数的类型,由传入参数和返回值决定,匿名函数也可以进行类型推断
和具名函数不同,除了极少数情况下,匿名函数不需要return关键字返回数据,匿名函数会隐式或自动返回函数体最后一行语句的结果
var blessingFun ={name:String,year:Int->
val holiday = "New Year"
"$name,$year,$holiday"
}
it关键字
定义只有一个参数的匿名函数时,可以使用it关键字来表示参数名,当参数大于一个时it不能使用
如上代码可以替换成
var blessingFun :(String)->String={
val holiday = "New Year"
"$it,$holiday"
}
简略写法
如果一个函数的lambda参数排在最后,或者是唯一的参数,name括住lambda值参的一对圆括号就可以省略
fun main() {
//简略写法
show("coke"){goods:String,num:Int ->
val currentYear = 2027
"${currentYear}年,双11${goods}促销倒计时${num}小时"
}//这个{}中的代码其实是参数
}
//具名函数 参数为匿名函数
private fun show (goods:String,getDiscountWords :(String,Int)->String){
val num = (0..24).shuffled().last()//.shuffled()打乱 .last()取最后
println(getDiscountWords(goods,num))
}
运行结果:
具名函数引用 (::)
要把函数作为参数传给其他函数使用,除了传lambda表达式,kotlin还提供了其他方法,传递函数引用,函数引用可以把一个具名函数转换成一个值参,使用lambda表达式的地方都可以使用函数引用
闭包
在Kotlin中,匿名函数能修改并引用定义在自己的作用域之外的变量,匿名函数引用这定义自身的函数里的变量,kotlin中的Lambda就是闭包
能接收函数或者返回函数的函数又叫做高级函数,高级函数广泛应用于函数式编程当中
//函数类型作为返回值
fun main() {
val getDiscountWords : (String)->String = configDiscountWords()
println(getDiscountWords("牙膏"))
}
fun configDiscountWords():(String)->String{
//局部变量
val num = (0..24).shuffled().last()
val currentYear = 2027
return {
"${currentYear}年,双11${it}促销倒计时${num}小时"
}
}
继承
Kotlin中继承使用 “ : ” 连接父类,后接父类的构造 父类需使用open关键字修饰 如下
先调用父类init在调用子类init,类似于java中的初始化代码块static{},但是init{}是在构建对象时执行
无主构造
若类不使用主构造,则后续继承类也不需要使用构造,即可去掉继承类的(),次构造可以调用父类构造super进行初始化,但是次构造的参数在其他地方无法引用
Null 安全
在Java中空指针异常经常出现,而kotlin对其进行了可空性改良,采用在类型后加?来进行null的赋值管理,不加不能赋null值,例:
安全调用操作符 ( ?. )
kotlin区分可空类型和非空类型,所以如果让一个可空类型变量运行,而他又有可能不存在,针对这种潜在危险,Kotlin不允许在可空类型值上直接调用函数,采用在变量后加?.调用,例:
编译器见到有安全调用操作符,所以它知道如何检查null值。如果遇到null值,它就跳过函数调用,而不是返回null值,这种写法可以实现链式调用
Kotlin |
let函数
安全调用允许在可空类型上调用函数,但是如果还想做点额外的事,比如创建新值,或者判断不为null就调用其他函数,就可以使用带let函数的安全调用操作符,可以在任何类型上调用let函数,它的主要作用是可以在指定作用域内定义一个或多个变量
fun main() {
var str:String? = null
var str1:String? = "butterfly"
var str2:String? = ""
println(judge(str))
println(judge(str1))
println(judge(str2))
}
fun judge(str : String?): String? {
//安全调用操作符
return str?.let{
//非空白的字符串
if (it.isNotBlank()){
it.uppercase()
}else{
"not null"
}
}
}
运行结果:
非空断言操作符 ( !!. )
?.是当变量为null时不会调用匿名函数,而如果一定想调用就需要非空断言操作符,!!.又称感叹号操作符,当变量值为null时,会抛出异常
Kotlin |
空合并操作符 ( ?: )
?:操作符的意思是,如果左边的求值结果为null,就直接使用右边的结果值,它也可以和let函数一起使用来代替 if/else 语句
var str:String? = null
var strWithSafe:String = str ?: "HelloWord" //基础用法
//代替 if/else
fun main (){
var str :String? = null
str = str?.let{
it.uppercase()
} ?: "HelloWord"
}
异常
异常的继承关系和try/catch写法与Java中无差别
Kotlin |
自定义异常
Kotlin |
先决条件函数
kotlin标准库提供的便利函数,使用这些内置函数,可以抛出带自定义信息的异常,这些便利函数又叫做先决条件函数,可以用它定义先决条件,条件必须满足,目标代码才能执行
- checkNotNull:如果参数为null,则抛出IllegalStateException,否则返回非null值
- require:如果参数为false,则抛出IllegalArgumentException
- requireNotNull:如果参数为null,则抛出IllegalStateException,否则返回非null值
- error:如果参数为null,则抛出IllegalStateException并且输出错误信息,否则返回非null值
- assert:如果参数为false,则抛出AssertError,并打上断言编译器标记
Kotlin |
String
substring()
字符串截取函数,与Java区别在于Kotlin中支持IntRange类型(表示一个整数范围的类型)的参数,until创建的范围不包括上限值(左闭右开)
Kotlin |
split()
split函数返回值与Java一样为List集合数据,Kotlin中List集合又支持解构语法特性,它允许在一个表达式中给多个变量赋值,解构常用来简化变量的赋值
Kotlin |
replace()
字符串替换函数比Java中的更加强大,它可以传入一个匿名函数,从而配合when操作所有符合条件的字符
Kotlin |
标准库函数
Apply
apply函数可看做一个配置函数,可以传入一个接收者,然后调用一系列函数来配置它以便使用,如果提供lambda给apply函数执行,它会返回配置好的接收者
Kotlin |
在调用一个个函数类配置接收者时,变量名就省略掉了,这是因为,在lambda表达式里,apply能让每个配置函数都作用于接收者,这种行为有时又叫做相关作用域,因为lambda表达式里的所有函数都是针对接收者的,或者说,它们是针对接收者的隐式调用
run
与applay不同的是,run函数不返回接收者,run返回的是lambda的结果
Kotlin |
run函数也可以执行具名函数引用( :: )
fun main{
val str = "fdsafdsafa"
println(str.run(::islong).run (::printLine)) //链式引用
}
fun islong(str:String):Boolean{
return str.length>=10
}
fun printLine(isLong:Boolean):String{
return if (isLong){
"str is toLong"
}else{
"is gerat"
}
}
With
with函数是run的变体,他们的功能和行为是一样的,但with的调用方式不同,调用with时需要值参作为其第一个参数传入
Kotlin |