Kotiln基础语法总结
Posted narkang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Kotiln基础语法总结相关的知识,希望对你有一定的参考价值。
kotlin不仅支持编写在虚拟机上运行,而且还是一门跨平台的通用型语言,我们可以用Kotlin开发各种类型的原生应用,如android,macOS,Windows,javascript应用。
Kotlin能脱离虚拟机层,直接编译成可以在Windows,Linux和macOS平台上运行的原生二进制代码。
一、变量
变量声明
//Int类型可以省略,自动推导
var max: Int = 5
//var 可读可写
//val 可读不可写
常用内置数据类型
类型 | 描述 | 示例 |
---|---|---|
String | 字符串 | ”Hello World“ |
Char | 单字符 | ‘A’ |
Boolean | true/false | true false |
Int | 整数 | 5 |
Double | 小数 | 3.14 |
List | 元素集合 | |
Set | 无重复元素的集合 | |
Map | 键值对集合 |
二、编译时常量
编译时常量只能在函数之外定义,因为编译时常量必须在编译时赋值,而函数都是在运行时才调用,函数内的变量也是在运行时赋值,编译时常量要在这些变量赋值前就已存在
编译时常量只能时常见的基本数据类型:String、Int、Double、Float、Long、Short、Byte、Char、Boolean
const val MAX = 100
三、查看Kotlin字节码
两种方式
1.Shift键两次,输入Show Kotlin
2.Tools->Kotlin->Show Kotlin Bytecode
Decompile可以反编译成java代码
四、Kotlin的引用类似与基本数据类型
Java有两种数据类型:引用类似与基本数据类型
Kotlin只提供引用类型这一种数据类型
,出于更高性能的需要,Kotlin的编译器会在Java字节码中引用基本数据类型
五、range表达式
//range
val age = 0
//0 .. 3 大于等于0小于等于3
if(age in 0 .. 3)
println("婴幼儿")
//4 .. 12 大于等于4小于等于12
else if(age in 4 .. 12)
println("少儿")
else
println("青少年")
//其他写法
if(age !in 0 .. 3)
else
range表达式是闭区间
六、when表达式
//when
val school = "小学"
when(school)
"学前班" -> "幼儿园"
"小学" -> "少儿"
"中学" -> "青少年"
else ->
println("未知")
允许你编写条件式,在某个条件满足时,执行相应的代码。只要代码包含else if
分支,都建议改用when表达式。
七、string模板
模板支持在字符串的引号内放入变量值,还支持字符串里计算表达式的值并插入结果,添加在$
中的任何表达式,都会作为字符串的一部分求值。
//String模板 StringTemplate
val orgin = "Jack"
val dest = "Rose"
println("$orgin love $dest")
val flag = true
println("Answer is $if(flag) "我可以" else "对不起"")
八、函数
可见修饰符默认是public
8.1、函数参数
默认参数
如果不打算传入值参,可以预先给参数指定默认值
具名函数参数
如果使用命名值参,就可以不用管值参的顺序
private fun doSomething(age: Int, flag: Boolean): String
return "result"
//函数可以加默认值
fun fix(name: String, age: Int = 2)
println(name + age)
fun main()
doSomething(flag = false, age = 12)
8.2、Unit函数
不是所有函数都有返回值,Kotlin中没有返回值的函数叫Unit函数,也就是说他们的返回类型是Unit。在Kotlin之前,函数不返回任何东西用void描述,意思是“没有返回类型,不会带来什么,忽略它”,也就是说如果函数不反悔任何东西,就忽略类型。但是,void这种解决方案无法解释现代语言的一个重要特征,泛型。
8.3、TODO函数
TODO函数的任务就是抛出异常,就是永远别指望它运行成功,返回Nothing类型
public inline fun TODO(): Nothing = throw NotImplementedError()
8.4、反引号的函数名
Kotlin可以使用空格和特殊字符对函数命名,不过函数名要用一对反引号括起来
为了支持Kotlin和Java互操作,而Kotlin和Java各自却有着不同的保留关键字,不能作为函数名,使用反引号括住函数名就能避免任何冲突
fun `is`()
九、匿名函数
定义时不取名字的函数,我们称之为匿名函数,匿名函数通常整体传递给其他函数,或者从其他函数返回
匿名函数对Kotlin来说很重要,有了它,我们能够根据需要制定特殊规则,轻松定制标准库里的内置函数
//如果一个函数的lambda参数排在最后,或者是唯一的参数,那么括住lambda值参的一对圆括号就可以省略
//字符串中s的个数
val total = "Mississipi".count(letter ->
letter == 's'
)
println(total)
匿名函数也有类型,匿名函数可以当作变量赋值给函数变量,就像其他变量一样,匿名函数就可以在代码里面传递了。
和具名函数不一样,除了极少数情况外,匿名函数不需要return关键字来返回数据,匿名函数会隐式或自动返回函数体最后一行语句的结果。
//声明一个变量,等于一个函数,就是函数的类型
//函数的类型由参数和返回值决定
val blessingFunction: ()->String =
val holiday = "New Year."
"Happy $holiday"
println(blessingFunction())
//传一个参数的时候,name参数可以用it替代
val blessingFunction2: (String)->String = name ->
"Happy $name"
println(blessingFunction2("New Year"))
//返回值类型推断
val blessingFunction3 = name: String ->
"Happy $name"
println(blessingFunction3("New Year"))
定义只有一个
参数的匿名函数时,可以使用it关键来表示参数名。当你需要传入两个值参,it关键字就不能用了。
9.1、lambda
我们将匿名函数称为lambda,将它的定义成为lambda表达式,它返回的数据称为lambda结果。
十、定义参数是函数的函数
函数的参数是另外一个函数
//显示促销的文案,文案由另外一个函数生成
fun showOnBoard(goodsName: String, getDiscountWords: (String, Int) -> String)
val hour = (1..24).shuffled().last();
println(getDiscountWords(goodsName, hour))
fun test03()
val getDiscountWords = goodsName: String, hour: Int ->
val currentYear = 2027
"$currentYear年, 双11$goodsName促销倒计时:$hour 小时"
showOnBoard("卫生纸", getDiscountWords)
//第二种写法 简略写法
showOnBoard("卫生纸") goodsName: String, hour: Int ->
val currentYear = 2027
"$currentYear年, 双11$goodsName促销倒计时:$hour 小时"
闭包是为了解决作用域问题
十一、函数内敛(inline)
在jvm上,你定义的lambda会以对象实例的形式存在,jvm会为所有同lambda打交道的变量分配内存,这就是内存开销。更糟的是,lambda的内存开销会带来严重的性能问题。幸运的是,kotlin有一种优化机制叫内敛,有了内敛,jvm就不需要使用lambda对象实例了,因而避免了变量内存分配。哪里需要使用lambda,编译器就会将函数体复制粘贴到哪里。
使用lambda的递归函数无法内敛,因为会导致粘贴无限循环,编译会发出警告。
十二、函数引用
fun getDiscountWords(goodsName: String, hour: Int): String
val currentYear = 2027
return "$currentYear年, 双11$goodsName促销倒计时:$hour 小时"
//显示促销的文案,文案由另外一个函数生成
fun showOnBoard(goodsName: String, getDiscountWords: (String, Int) -> String)
val hour = (1..24).shuffled().last();
println(getDiscountWords(goodsName, hour))
showOnBoard("卫生纸", ::getDiscountWords)
十三、闭包
在Kotlin中,匿名函数能修改并引用定义在自己的作用域之外的变量,匿名函数引用着定义自身的函数里的变量,Kotlin中的lambda就是闭包
能接受函数或者返回函数的函数又叫高级函数,高级函数广泛应用于函数式编程当中
//闭包
fun configDiscountWords(): (String) -> String
return goodsName: String ->
val currentYear = 2027
val hour = (1..24).shuffled().last();
"$currentYear年, 双11$goodsName促销倒计时:$hour 小时"
val getDiscountWords = configDiscountWords()
println(getDiscountWords("牙膏"))
函数类型能让开发者少写模式化代码,写出更灵活的代码。java8支持面向对象编程和lambda表达式,但不支持将函数作为参数传给另一个函数或变量,不过java的替代方案是匿名内部类。
十四、null
kotlin更多地把运行时可能会出现的null问题,以编译时错误的方式,提前在编译期强迫我们重视起来,而不是等到运行时报错,防范于未然,提高了我们程序的健壮性。
对于null值问题,Kotlin反其道而行之,除非另有规定,变量不可为null值,这样一来,运行时崩溃从根源上得到解决。
var str: String = "abc"
str = null //编译报错
var str2: String? = readLine()
str2 = null
Kotlin区分可空类型和非可空类型,所以,你要一个可空类型变量运行,而它又可能不存在,对于这种潜在危险,编译器时刻警惕着,为了应对这种风险,kotlin不允许你在可空类型上调用函数,除非你手动接手安全管理。
三种类型操作空值
- 选项一:安全调用操作符
?.
如果遇到null值,它就跳过函数调用,而不是返回null。
var str2: String? = readLine()?.capitalize()
-
使用非空断言操作符
!!.
-
使用
if
判断
十五、空合并操作符 ?:
如果左边的求职结果为null,就使用右边的结果值
var str: String? = str?: "butterfly"
十六、异常
//自定义异常
class UnskilledException(): IllegalStateException("操作不合法")
fun checkOperation(number: Int?)
number ?: throw UnskilledException()
fun testException()
var number: Int? = null
//处理异常
try
number!!.plus(1)
catch (e: Exception)
println(e)
十七、先决条件函数
Kotlin标准库提供了一些便利函数,使用这些内置函数,你可以抛出带自定义信息的异常,这些便利函数叫做先决条件函数,你可以用它定义先决条件,条件必须满足,目标代码才能执行
kotlin都是运行时异常(未检查异常),可以不try catch
,非运行异常(检查异常)都是通过编译器报错来处理的。
十八、字符串操作
18.1、substring
字符串截取,substring函数支持IntRange类型(表示一个函数范围的类型)的参数,until创建的范围不包括上限值。
val name = "Jimmy's friends"
val index = name.indexOf('\\'')
//支持IntRanger
val str = name.substring(0 until index)
18.2、split和解构赋值
split函数返回的是List集合数据,List集合又支持解构语法特性,它允许你在一个表达式里给多个变量赋值,解构常用来简化变量的赋值。
//解构赋值
val name = "Jimmy,friends,hello"
val (a, b, c) = name.split(',')
println("$a,$b,$c")
18.2、replace 字符串替换
val name = "Jimmy,friends,hello"
val str = name.replace(Regex("[aeiou]"))
when(it.value)
"a" -> "8"
"e" -> "4"
else ->it.value
println(str)
18.3、字符串比较
在kotlin中,用==
检查两个字符串中的字符是否匹配,用===
检查两个变量是否指向堆上同一个对象,而在Java中==
做引用比较,做结构比较时用equals
方法。
val str1 = "Jack"
val str2 = "Jack"
println(str1 == str2) //true
println(str1 === str2) //true
val str1 = "Jack"
val str2 = "jack".capitalize()
println(str1 == str2) //true
println(str1 === str2) //false
18.4、forEach
val name = "Jimmy,friends,hello";
name.forEach
println("$it*")
十九、数字类型
和Java一样,Kotlin中所有数字类型都是有符号的,也就是说既可以表示正数,也可以表示负数
19.1、安全转换函数
kotlin提供了toDoubleOrNull
和toIntOrNull
这样的安全转换函数,如果数值不能正确转换,与其触发异常不如干脆返回null值
val number:Int? = "8.98".toIntOrNull() //null
19.2、Double类型格式化
格式化字符串是一串特殊字符,它决定该如何格式化数据。
//8.99 会四舍五入
val s = "%.2f".format("8.987899")
//精度损失
val number2:Int? = 8.98.toInt()
//四舍五入
val number3:Int? = 9.98.roundToInt()
二十、标准库函数
20.1、apply
apply函数可看作一个配置函数,你可以传入一个接收者,然后调用一系列函数来配置它以便使用,如果提供lambda给apply函数执行,它会返回配置好的接收者
val file = File("D://I have a dream_copy.txt")
file.setReadable(true)
file.setWritable(true)
file.setExecutable(false)
val file2 = File("D://I have a dream_copy.txt")
.apply
setReadable(true)
setWritable(true)
setExecutable(false)
可以看到,调用一个个函数类配置接收者时,变量名就省掉了,这是因为,在lambda表达式里,apply能让每个配置函数都作用于接收者,这种行为有时又叫做相关作用域,因为lambda表达式里的所有函数调用都是针对接收者的,或者说,它们是针对接收者的隐式调用。
20.2、let函数
let函数能使某个作用于其lambda表达式里,让it关键字能引用它。let与apply比较,let会把接收者传给lambda,而apply什么都不传,匿名函数执行完,apply会返回当前接收者,而let会返回lambda的最后一行。
val result = listOf(3, 2, 1).first().let it * it
20.3、run函数
run和apply差不多,但与apply不同,run函数不返回接收者,run返回的是lambda结果,也就是true或者false。
val file = File("D://I have a dream_copy.txt")
file.run
readText().contains("great")
val flag:Boolean = "I have a dream_copy".run(::isTooLong)
//链式调用写法
"I have a dream_copy"
.run(::isTooLong)
.run(::showMessage)
.run(::println)
20.4、with函数
with函数是run的变体,他们的功能行为是一样的,但with的调用方式不同,调用with时需要值参作为其第一个参数传入。
with("I have a dream_copy")
length > 0
20.5、also
also函数和let函数功能相似,和let一样,also也是把接收者作为值参传给lambda,但有一点不同:also返回接收者对象,而let返回lambda结果。因为这个差异,also尤其适合针对同一原始对象,利用副作用做事,既然also返回的是接收者对象,你就可以基于原始接收者对象执行额外的链式调用。
var fileContents: List<String>
File("D://I have a dream_copy.txt")
.also
println(it.name)
.also
fileContents = it.readLines()
println(fileContents)
20.6、takeIf
和其他标准函数有点不一样,takeIf函数需要判断lambda中提供的条件表示式,给出true或false结果,如果判断结果式true,从takeIf函数返回接收者对象,如果式false,则返回null。如果需要判断某个条件是否满足,再决定是否可以赋值变量或执行某项任务
,takeIf就非常有用,概念上讲,takeIf函数类似于if语句,但它的优势是可以直接在对象实例上调用,避免了临时变量赋值的麻烦。
var fileContents = File("D://I have a dream_copy.txt")
.takeIf it.exists() ?.readText()
20.7、takeUnless
takeIf辅助函数takeUnless,只有判断你给定的条件结果是false,takeUnless才是返回原始接收者对象。
var fileContents = File("D://I have a dream_copy.txt")
.takeUnless it.isHidden ?.readText()
二一、List
getOrElse是一个安全索引取值函数,它需要两个参数,第一个是索引值,第二个是能提供默认值的lambda表达式,如果索引值不存在的话,可用来代替异常。
getOrNull是Kotlin提供的另一个安全索引取值函数,它返回null结果,而不是抛出异常。
//list集合 只读
val listOf = listOf("Jason", "Jack", "Jacky").distinct() //distinct去重
//越界了不会抛异常,而是可以交给lambda处理
listOf.getOrElse(4)"UnKnow"
listOf.getOrNull(4)?: "UnKnow"
listOf.toMutableList()
//可写
val mutableListOf = mutableListOf("Jason", "Jack", "Jacky")
mutableListOf.add("Jimmy")
mutableListOf.remove("Jimmy")
mutableListOf += "Jimmy"
mutableListOf -= "Jimmy"
mutableListOf.toList()
21.1、mutator函数
能修改可变列表的函数有个统一的名字:mutator函数
添加元素运算符与删除元素运算符
基于lambda表达式指定的条件删除元素
21.2、集合遍历
for in
遍历
forEach
遍历
forEachIndexed
遍历时要获取索引
val listOf = listOf("Jason", "Jack", "Jacky").distinct() //distinct去重
listOf.forEach
println(it)
以上是关于Kotiln基础语法总结的主要内容,如果未能解决你的问题,请参考以下文章