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)
}
listOf.forEachIndexed{index, item ->
    //带索引
    println("$index $item")
}

21.4、解构

通过_符号过滤不想要的元素

val (origin, _, proxy) = listOf("Jason", "Jack", "Jacky").distinct() //distinct去重

二二、set


通过setOf创建set集合,使用elementAt函数读取集合中的元素

//只读
val set = setOf("Jack", "Jason", "Jacky")
set.elementAt(1)

//可写
val mutableSetOf = mutableSetOf("Jack", "Jason", "Jacky")
mutableSetOf += "Kit"

//快捷函数去重
listOf("Jason""Jack", "Jack", "Jacky").distinct() //去重

22.1、数组类型

Kotlin提供各种Array,虽然是引用类型,但可以编译成Java基本数据类型

在这里插入图片描述

val intArrayOf = intArrayOf(10, 30, 40, 20)
listOf(10, 20, 30).toIntArray()
val arrayOf = arrayOf(File("xx"))

二三、map


to看上去像关键字,但事实上,它是个省略了点号和参数的特殊函数,to函数将它左边和右边的值转换成一对Pair。

//只读
val mapOf = mapOf("Jack" to 18, "Jo" to 20, "Ka" to 30)
//可变
val mutableMapOf = mutableMapOf("Jack" to 18, "Jo" to 20, "Ka" to 30)
mutableMapOf += Pair("Jas", 18)
mutableMapOf.put("Jimmy", 31)
mutableMapOf.getOrPut("Jac"){18}

23.1、读取Map的值

[]取值运算符,读取键对应的值,如果键不存在就返回null
getValue,读取对应的值,如果键不存在就抛出异常
getOrElse,读取键对应的值,或者使用匿名函数返回默认值
getOrDefault,读取键对应的值,或者返回默认值

mapOf.getValue("Jimmy")
mapOf.getOrElse("Jimmy"){10}
mapOf.getOrDefault("Jimmy", 10)

mapOf.forEach{
   println("${it.key}, ${it.value}")
}

mapOf.forEach{(key, value) ->
   println("${key}, ${value}")
}

二四、field


针对你定义的每一个属性,Kotlin都会产生一个field,一个getter、以及setter,field用来存储属性数据,你不能直接定义field,Kotlin会封装field,保护它里面的数据,只暴露给getter和setter使用。属性的getter方法决定你如何读取属性值,每个属性都有getter方法,setter方法决定你如何给属性赋值,所以只有可变属性才有setter方法,尽管Kotlin会自动提供默认的getter和setter方法,但在需要控制如何读写属性数据时,你也可以自定义他们。

class Player{

    var name = "abc"
        get() = field.capitalize()
        set(value) {
            field = value.trim()
        }

    var age = 10
        get() = field.absoluteValue
        set(value) {
            field = value.absoluteValue
        }
	//计算属性是通过一个覆盖的get或set运算符来定义,这时field就不需要了
    val rolledValue
    	//每次都是变动的
        get() = (1..6).shuffled().first()

}
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值