变量
1 2 3 4 5 6
|
var price: Int = 100;
|
Kotlin 支持类型推导,大部分情况下,我们的变量类型可以省略不写
我们应该尽可能避免使用 var,尽可能多地去使用 val
- val 声明的变量,我们叫做不可变变量,它的值在初始化以后就无法再次被修改,它相当于 Java 里面的 final 变量。
- var 声明的变量,我们叫做可变变量,它对应 Java 里的普通变量。
基础类型
在 Kotlin 语言体系当中,是没有原始类型这个概念的。这也就意味着,在 Kotlin 里,一切都是对象。
虽然 Kotlin 在语法层面摒弃了“原始类型”,但有时候为了性能考虑,我们确实需要用“原始类型”。这时候我们应该怎么办?(TODO 后面会讲)
1
| val i: Double = 1.toDouble()
|
空安全
1 2
| val i: Double = null val j: Double? = null
|
由于 Kotlin 对可能为空的变量类型做了强制区分,这就意味着,“可能为空的变量”无法直接赋值给“不可为空的变量”,当然,反向赋值是没有问题的。
1 2 3 4 5
| var i: Double = 1.0 var j: Double? = null
i = j j = i
|
数字类型
1 2 3 4 5 6
| val int = 1 val long = 1234567L val double = 13.14 val float = 13.14F val hexadecimal = 0xAF val binary = 0b01010101
|
- 整数默认会被推导为“Int”类型;
- Long 类型,我们则需要使用“L”后缀;
- 小数默认会被推导为“Double”,我们不需要使用“D”后缀;
- Float 类型,我们需要使用“F”后缀;
- 使用“0x”,来代表十六进制字面量;
- 使用“0b”,来代表二进制字面量。
Java 可以隐式转换数字类型,而 Kotlin 更推崇显式转换。
1 2
| int i = 100; long j = i;
|
1 2 3 4 5
| val i = 100 val j: Long = i
val i = 100 val j: Long = i.toLong()
|
Kotlin 这样设计的优势也是显而易见的,我们代码的可读性更强了,将来也更容易维护了。
字符:Char
1 2 3 4 5
| val c: Char = 'A' val i: Int = c
val c: Char = 'A' val i: Int = c.toInt()
|
字符串:String
Kotlin 还为我们提供了非常简洁的字符串模板:
1 2 3 4 5 6 7
| val name = "Kotlin" print("Hello $name!")
Hello Kotlin!
|
1 2 3 4 5 6 7
| val array = arrayOf("Java", "Kotlin") print("Hello ${array.get(1)}!")
Hello Kotlin!
|
Kotlin 还新增了一个原始字符串,它定义的时候是什么格式,最终打印也会是对应的格式
1 2 3 4 5 6
| val s = """ 当我们的字符串有复杂的格式时 原始字符串非常的方便 因为它可以做到所见即所得。 """
print(s)
|
数组
1 2
| val arrayInt = arrayOf(1, 2, 3) val arrayString = arrayOf("apple", "pear")
|
Kotlin 编译器也会根据传入的参数进行类型推导。
虽然 Kotlin 的数组仍然不属于集合,但它的一些操作是跟集合统一的。
1 2 3 4 5 6 7
| val array = arrayOf("apple", "pear") println("Size is ${array.size}") println("First element is ${array[0]}")
Size is 2 First element is apple
|
函数声明
1 2 3 4 5 6 7 8
|
fun helloFunction(name: String): String { return "Hello $name !" }
|
它的函数体实际上只有一行代码。那么针对这种情况,我们其实就可以省略函数体的花括号,直接使用“=”来连接,将其变成一种类似变量赋值的函数形式:
1
| fun helloFunction(name: String): String = "Hello $name !"
|
称之为单一表达式函数
由于 Kotlin 支持类型推导,我们在使用单一表达式形式的时候,返回值的类型也可以省略:
1
| fun helloFunction(name: String) = "Hello $name !"
|
函数调用
Kotlin 提供了一些新的特性,那就是命名参数,在调用函数的时候传入“形参的名字”。
1
| helloFunction(name = "Kotlin")
|
针对参数较多的函数,我们一般会以纵向的方式排列
1 2 3 4 5 6 7 8 9 10 11
| fun createUser( name: String, age: Int, gender: Int, friendCount: Int, feedCount: Int, likeCount: Long, commentCount: Int ) { }
|
1 2 3 4 5 6 7 8 9
| createUser( name = "Tom", age = 30, gender = 1, friendCount = 78, feedCount = 2093, likeCount = 10937, commentCount = 3285 )
|
体现出了 Kotlin 命名参数的可读性与易维护性两个优势。
Kotlin 还支持参数默认值
1 2 3 4 5 6 7 8 9 10 11
| fun createUser( name: String, age: Int, gender: Int = 1, friendCount: Int = 0, feedCount: Int = 0, likeCount: Long = 0L, commentCount: Int = 0 ) { }
|
对于有默认值的参数,则可传可不传
1 2 3 4 5
| createUser( name = "Tom", age = 30, commentCount = 3285 )
|
流程控制
if
它还可以作为表达式(Expression)来使用
1 2 3 4 5 6 7
| val i = 1 val message = if (i > 0) "Big" else "Small"
print(message)
输出结果: Big
|
我们会经常遇到可空的变量,并且要判断它们是否为空。
1 2 3
| fun getLength(text: String?): Int { return if (text != null) text.length else 0 }
|
Kotlin 针对这种情况就提供了一种简写,叫做 Elvis 表达式。
1 2 3
| fun getLength(text: String?): Int { return text?.length ?: 0 }
|
when
大于两个逻辑分支的情况下,我们使用 when
1 2 3 4 5 6 7 8 9 10
| val i: Int = 1
when(i) { 1 -> print("一") 2 -> print("二") else -> print("i 不是一也不是二") }
输出结果: 一
|
它同时也可以作为表达式,为变量赋值
1 2 3 4 5 6 7 8 9
| val i: Int = 1
val message = when(i) { 1 -> "一" 2 -> "二" else -> "i 不是一也不是二" }
print(message)
|
when 表达式要求它里面的逻辑分支必须是完整的,如果去掉 else 分支,编译器将报错
循环迭代:while 与 for
Kotlin 的 for 语句更多的是用于“迭代”
1 2 3 4
| val array = arrayOf(1, 2, 3) for (i in array) { println(i) }
|
除了迭代数组和集合以外,Kotlin 还支持迭代一个“区间”。
1 2 3 4 5 6 7 8
| for (i in oneToThree) { println(i) }
输出结果: 1 2 3
|
还可以逆序迭代一个区间
1 2 3 4 5 6 7 8 9
| for (i in 6 downTo 0 step 2) { println(i) }
输出结果: 6 4 2 0
|
从 6 到 0,每次迭代的步长是 2,这意味着 6 迭代过后,到 4、2,最后到 0。
需要特别注意的是,逆序区间我们不能使用“6..0”来定义,如果用这样的方式来定义的话,代码将无法正常运行。
Kotlin优化点
- 支持类型推导;
- 代码末尾不需要分号;
- 字符串模板;
- 原始字符串,支持复杂文本格式;
- 单一表达式函数,简洁且符合直觉;
- 函数参数支持默认值,替代 Builder 模式的同时,可读性还很强;
- if 和 when 可以作为表达式。
同时,JetBrains 也非常清楚开发者在什么情况下容易出错,所以,它在语言层面也做了很多改进:
- 强制区分“可为空变量类型”和“不可为空变量类型”,规避空指针异常;
- 推崇不可变性(val),对于没有修改需求的变量,IDE 会智能提示开发者将“var”改为“val”;
- 基础类型不支持隐式类型转换,这能避免很多隐藏的问题;
- 数组访问行为与集合统一,不会出现 array.length、list.size 这种恼人的情况;
- 函数调用支持命名参数,提高可读性,在后续维护代码的时候不易出错;
- when 表达式,强制要求逻辑分支完整,让你写出来的逻辑永远不会有漏洞。
关注我