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’
Booleantrue/falsetrue 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提供了toDoubleOrNulltoIntOrNull这样的安全转换函数,如果数值不能正确转换,与其触发异常不如干脆返回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基础语法总结的主要内容,如果未能解决你的问题,请参考以下文章

Kotiln基础语法总结

Kotiln基础语法总结

Kotiln基础语法总结

Kotiln基础语法总结

Kotiln基础语法总结

Kotiln基础语法总结