Kotlin
Java相对于Kotlin对比,Java的语法太繁琐,Kotlin更现代化, 语法更方便简洁, 可以作为更好的一个替代。Kotlin解决了Java中很多的痛点,进化成一门优秀的语言,给开发者带来了更可靠的开发体验。Kotlin可以编译成Java字节码,也可以编译成JavaScript,方便在没有JVM的设备上运行。除此之外Kotlin还可以编译成二进制代码直接运行在机器上(例如嵌入式设备或 iOS)。
为什么学习 Kotlin?
- 2019 年,谷歌I/O 大会上则宣布 Kotlin 是 Android 应用开发的首选语言。
- 简洁: 语法简洁,大大减少样板代码的数量。
- 安全: 减少应用崩溃,避免空指针异常等整个类的错误。
- 互操作性: 可以和Java互相操作。
其它Kotlin文章
Android学习Kotlin之一、常量-条件-函数-高阶函数
Android学习Kotlin之二、Null安全 -字符串操作- 类型转换
Android学习Kotlin之三、标准库函数-集合List-Set-Map
Android学习Kotlin之四、定义类-初始化-继承
Android学习Kotlin之五、对象-接口-抽象类
Android学习Kotlin之六、泛型-扩展函数
本编文章会讲到的知识点
- 变量与类型
- 数据类型
- 数字类型
- 变量
- 类型推算
- 查看Kotlin字节码
- Kotlin的引用类型和基本数据类型
- 条件语句
- if else
- range
- when
- string模板
- 函数
- 定义函数
- 函数参数
- Unit函数
- 反引号中的函数名
- 高阶函数
- 匿名函数
- 函数类型与隐式返回
- 匿名函数参数
- it关键值
- 类型推断
- 参数为函数
- 简略传函数参
- 函数引用
- 函数类型作为返回类型
- 闭包
- lambda与匿名内部类
变量与类型
数据类型
kotlin内置数据类型
类型 | 描述 | 示例 |
---|---|---|
String | 字符串 | "Hello kotlin" |
Char | 单字符 | "A" |
Boolean | 布尔值 | true\false |
Number | 数值 | Byte Short Int Long Float Double |
Array | 集合 | List Set Map |
数字类型
和java一样,kotlin中所有的数字类型都是有符号的,可以有正有负,长度各不相同。
类型 | 位 | 最大值 | 最小值 |
---|---|---|---|
Byte | 8 | 127 | -128 |
Short | 16 | 32767 | -32768 |
Int | 32 | 2147483647 | -2147483648 |
Long | 64 | 9223372036854775807 | -9223372036854775808 |
Float | 32 | 3.4028235E38 | 1.4E-45 |
Double | 64 | 1.7976931348623157E308 | 4 9E-324 |
变量
声明变量
- var可变变量 可改变值
var age: Int = 18
age++ //可改变
- val只读变量 只能赋值一次
val name: String = "甜心"
name = "baby" // 会报错 使用val定义的变量是不可改变的只能赋值一次
类型推算
对于已声明并赋值的变量,它允许你省略类型定义自动推算类型
var love = "敲键盘" //自动推算类型为String
查看Kotlin字节码
查看Kotlin编译后的字节码,有助于深入了解Kotlin语言
两种方式:
- Shift两次,输入Show Kotlin
-
Tools>Kotlin>Show Kotlin Bytecode
Kotlin的引用类型和基本数据类型
- Java有两种数据类型,一种引用类型一种基本数据类型。
- Kotlin只有引用类型这一种类型,出于更高性能的需要,Kotlin编译器会在Java字节码中改用基本数据类型。
条件语句
if else
- java一样
if (age>18) {
println("成年了")
} else {
println("未成年")
}
- 简写方式
println(if (age>18) "已经成年2" else "未成年2")
range
Range是Kotlin相对Java新增的一种表达式,它表示的是值的范围,类似于数学中的区间。Range的表达式是像这样子的:1..20,其中..是运算符,它表示一个闭区间[1, 20]。而右开区间用until表示:1 until 20,即[1, 20)
- Range表达式一般是和in和!in操作符一起使用,表示是否包含在该区间内
if (a in 2..10) {//相当于 i >= 2 && i <= 20
println("我在区间")
}
if (a !in 2..10) {//相当于 i < 2 && i > 20
println("我不在区间")
}
- 对于一些整形的range(IntRange、LongRange、CharRange)是可以进行迭代的,它们可以和for循环一起使用
for (i in 1..6) println(i)//输出123456
- 使用downTo()函数可以对range进行倒序迭代
for (i in 6 downTo 1) println(i)//输出654321
- 使用step()函数,这里指定为2,则每次遍历后会以2个为单位遍历
for (i in 8..16 step 2) println(i)//输出8 10 12 14 16
when
when,大家都会联想到 Java 中的 switch,然而在 kotlin 中,when 显然比 Java 中的 switch 要强大得多。when 既可以被当做表达式使用也可以被当做语句使用。如果它被当做表达式。
- 作为表达式使用,也可以将代码块作为我们的分支体,这时候代码块中最后一个表达式或者变量就是该分支体的返回结果
var n = "小芳"
var m = when (n) {
"小明" -> "我是小明"
"小芳" -> {
println("lailai")
"我是小芳芳"
}
"小强" -> "我是小强"
else -> "未知人"
}
println(m)//打印 lailai 我是小芳芳
- 作为语句使用
when (n) {
"小明" -> println("我是小明2")
"小芳" -> println("我是小芳2")
"小强" -> {
println("我是小强2")
}
else -> println("未知人2")
}
- 可以检测一个值在(in)或者不在(!in)一个区间或者集合中
when (6) {
in 1..10 -> {
var n = 10
println(n)
}
else -> print(66)
}
- 检测一个值是(is)或者不是(!is)一个特定类型的值,可以直接使用类型的属性和方法
var x = "love"
when (x) {
is String -> println("love长度= " + x.length)
else -> false
}
- 无参使用,if else if可以改成这样
when {
x?.length==4 -> print("长度对的")
else -> print("长度不对")
}
string模板
模板支持在字符串的引号内放入变量值;还支持字符串里计算表达式的值并插入结果,添加在${}中的任何表达式,都会作为字符串的一部分求值。
val man = "沈腾"
val woman ="贾玲"
println("$man love $woman")// 打印 沈腾 love 贾玲
val falg =false
println("我爱的人是:${if (falg) "邓紫棋" else "张靓颖"}")//打印 我爱的人是:张靓颖
函数
定义函数
private fun doSomething(age:Int,flag:Boolean) :String{
return "运动"
}
函数参数
- 默认值参数
如果不打算传入参数,可以给参数设置默认值
private fun setStudent(name:String,age:Int=18){
println("名字:$name , 年龄:$age")
}
setStudent("郑恺")//没有传age 打印 “名字:郑恺 , 年龄:18”
setStudent("郑恺",38)//打印 “名字:郑恺 , 年龄:38”
- 具名函数参数
使用参数命名值传参,就不用管函数中参数的顺序了
private fun setMotion(motion1:String,motion2:String,motion3:String){
println("运动1:$motion1 , 运动2:$motion2, 运动3:$motion3")
}
setMotion(motion2="游泳",motion1 = "乒乓",motion3 = "爬山")// “运动1:乒乓 , 运动2:游泳, 运动3:爬山“
- Unit函数
Java中没有返回值的函数定义void类型,而kotlin没有返回值定义Unit返回类型,默认可以不写。
private fun setStudent(name:String,age:Int=18):Unit{
}
private fun setStudent(name:String,age:Int=18){
}
反引号中的函数名
kotlin可以使用空格和特殊字符对函数命名,但是函数名需要用双引号括起来。Kotlin和Java可以互相调用函数,而kotlin和Java各自有着不同的保留关键字不能作为函数名,使用反引号可以解决冲突。
private fun `123`():Int{
return 666
}
private fun `class`():String{
return "class"
}
println(`123`())
println(`class`())
高阶函数
匿名函数
定义时不取名字的函数,我们称之为匿名函数,匿名函数通常整体传递给其它函数或者从其它函数中返回。
- 定义匿名函数和调用, {}是匿名函数 ()是调用匿名函数可以传值 匿名函数不支持参数默认值和具名函数参数。
println({a: Int, b: String ->
"Welcome to HangZhou, $a!(copyright $b)"
}(2021, "磐石"))
- 定义标准库中的函数规则
//count()函数是获取字符个数
var totalNum:Int = "missyous".count { letter ->
letter == 's'
}
println("共有s个数=:"+totalNum)
函数类型与隐式返回
匿名函数也有类型,匿名函数可以当做变量赋值给函数类型变量,和其它变量一样,匿名函数就可以在代码里传递了。函数类型由传入的参数和返回值类型决定。
匿名函数一般不需要return关键字来返回数据,那么为了返回数据,匿名函数会隐式返回函数体最后一行语句的结果。
//定义一个函数nowFun返回类型是String
val nowFun:()->String
nowFun = {
val name= "西塘河"
"你好 $name"
}
// 简写
val nowFun:()->String= {
val name= "西塘河"
"你好 $name"
}
println(nowFun()) // 打印 “你好 西塘河”
匿名函数参数
参数的类型放在匿名函数的类型定义中,参数名则放在函数定义中
var nowFun2: (String,Int) -> String = {name,age->
"你好 $name 年龄 $age"
}
println(nowFun2("马云",50))// 打印 “你好 马云 年龄 50”
it关键值
定义只有一个参数匿名函数时,可以使用it关键字当做参数名,当参数大于1个时it就不能用了。
var oneParamFun: (String) -> String = {
"我喜欢:$it"
}
println(oneParamFun("林忆莲"))// 打印 “我喜欢:林忆莲”
类型推断
定义一个函数变量时,如果已经把匿名函数赋值给了变量,就不用指定变量类型里了。有参数时,匿名函数的参数名和类型都必须有
//省略前
val typeFun:()->String = {
"我喜欢:"
}
//省略后
val typeFun = {
"我喜欢:"
}
println(typeFun())
//省略前
val typeParamFun:(String,String)->String = { name, yarn ->
"Happy $name $yarn"
}
//省略后
val typeParamFun = { name: String, yarn: String ->
"Happy $name $yarn"
}
println(typeParamFun("彭彭", "2025"))
参数为函数
在函数参数中可以传入函数,可以是匿名函数也可以是普通函数。
val setTime={goodName:String,yarn:Int->
"$yarn 天猫双十一 $goodName"
}
fun showTime(name:String, showGood:(String,Int)->String){
val yarn = (2020..2030).shuffled().last()
println(showGood(name,yarn))
}
showTime(name = "关晓彤",setTime)
简略传函数参
如果一个函数的lambda参数排在最后或者是唯一的参数,那么括住lambda值的圆括号就可以省略掉了。
showTime(name = "容祖儿"){goodName:String,yarn:Int->
"$yarn 天猫双十一 $goodName"
}
函数引用
上面讲过了 把函数当成参数传给一个函数使用,不光可以传递匿名函数也可以传递具名函数的引用,只要可以使用lambda表达式地方都可以使用函数引用。
fun setStudent(name:String,age:Int):String{
return "我是六年级的 $name 今年 $age 岁了"
}
fun setClass(name:String,student:(String,Int)->String){
println(student(name,12))
}
setClass("黄晓明", ::setStudent)//打印 “我是六年级的 黄晓明 今年 12 岁了”
函数类型作为返回类型
一个函数的返回值可以使一个函数(包括匿名函数和具名函数)。
fun getFruit():(String)->String{
val currYarn = 2021
return {fruitName:String->
"$currYarn 我喜欢吃 $fruitName"
}
}
val fruit = getFruit()//返回的是个匿名函数
println(fruit("樱桃"))// 打印 “2021 我喜欢吃 樱桃”
闭包
在Kotlin中,匿名好处能够修改并应用定义在自己的作用域之外的变量,匿名函数引用着定义自身的函数里的变量,Kotlin中的lambda就是闭包。
能接收函数或者返回函数的函数又叫做高级函数,高级函数广泛用于函数式编程当中。
lambda与匿名内部类
为什么要在代码中使用函数类型?函数类型能让开发者少写模式化代码,写出更灵活的代码。Java8支持lambda表达式,但不支持将函数作为参数传递给另一个函数或者变量,不过Java的替代方案是匿名函数。
- Kotlin使用匿名函数
kotlin使用匿名内部类直接创建就行
//定义一个函数最后一个参数是lamdba匿名函数
fun setPhone(phoneName: String, moneyDeta: (String, Int) -> Unit) {
val money = if (phoneName == "iphone12") 5800 else 6000
moneyDeta(phoneName, money)
}
// 调用函数传入一个lamdba匿名函数
setPhone("iphone12") { phoneName: String, money: Int ->
println("$phoneName 价格为 $money")
}
- Java中使用匿名函数
java使用匿名内部类需要先创建一个接口
public static void main(String[] args) {
// 通过new一个匿名内部类传过去
setPhone("iphone12", new MoneyDeta() {
@Override
public void setMoney(String phoneName, int money) {
System.out.println(phoneName+" 价格为 "+ money);
}
});
}
public static void setPhone(String phoneName,MoneyDeta moneyDeta){
int money = "iphone12".equals(phoneName)? 5800:6000;
moneyDeta.setMoney(phoneName,money);
}
//定义接口
public interface MoneyDeta{
void setMoney(String phoneName,int money);
}