Kotlin语法简洁,主要的几种区别或重点如下:
- 不用分号结尾
- 没有new关键字
- “:”很重要
- 参数名在前,类型在后
- …
包的定义
包的指定需要位于源文件的最顶部。(和Java相同)示例如下:
package com.xingfeng_coder.basic.syntas
/**
* Created by Xingfeng on 2017-06-12.
*/
函数的定义
- 下面的函数定义有两个Int形参并且返回值是Int类型,代码如下:
fun sum_1(a: Int, b: Int): Int {
return a + b
}
- 下面的函数使用表达式并自动推出返回值,代码如下:
fun sum_2(a: Int, b: Int) = a + b
- 下面的函数的返回值为没有意义的值,代码如下:
fun printSum_1(a: Int, b: Int): Unit {
println("sum of $a and $b is ${a + b}")
}
- Unit可以省略,函数定义如下:
fun printSum_2(a: Int, b: Int) {
println("sum of $a and $b is ${a + b}")
}
变量的定义
只赋值一次(只读)变量
val a: Int = 1 //声明并赋值
val b = 2 //声明并赋值,但是类型需要推断
val c: Int //先声明
c = 3 //后赋值
// b = 1 //尝试修改b的值,报错
从上面可以看出,只读变量类似Java中的final字段,需要使用val关键字进行声明变量。
可变变量
var x = 3
x += 1
println(x)
变量的定义使用var关键字,结果输出为4
注释
这个没有好说的
/**
* 演示变量的定义,包括常量和变量
*/
//声明并赋值
使用字符串模板
fun main(args: Array<String>) {
var a=1
val s1="a is $a"
a=2
val s2="${s1.replace("is","was")},but now is $a"
println(s1)
println(s2)
}
运行结果如下:
a is 1
a was 1,but now is 2
模板表达式由”$”符开始,并由一个简单的名称组成,也可以是{}括号表示的任意表达式。
比如下面的代码:
val s = "abc"
val str = "$s.length is ${s.length}"
str的值这儿就表示”abc.length is 3”
条件表达式
先看下面一个找出两个数中较大数的函数:
fun maxOf(a: Int, b: Int): Int {
if (a > b) {
return a
} else {
return b
}
}
使用if表达式,可以改写成如下形式:
fun maxOfUsingIfExpress(a: Int, b: Int) = if (a > b) a else b
If表达式
在Kotlin中,if是一个表达式,它返回一个值。因此Kotlin不提供三元运算符(condition?then:else),因此if表达式就可以很好地取代该功能。
// 传统用法
var max = a
if (a < b) max = b
// 使用if-else
var max: Int
if (a > b) {
max = a
} else {
max = b
}
// 使用if表达式
val max = if (a > b) a else b
如果if的分支是语句块,那么最后一个表达式就是该块的返回值:如下:
val max2 = if (a > b) {
print(a)
a
} else {
print(b)
b
}
使用可能为null的值并且检查null类型
当一个引用指向的值可能为null的时候,那么需要显式地指明该引用可能为null。
下面的函数将会在str转换不了整形时返回null
fun parseInt(str: String): Int? {
//模拟转换
return if (str.equals("1")) 1 else null
}
fun printProduct(arg1: String, arg2: String) {
val x = parseInt(arg1)
val y = parseInt(arg2)
if (x != null && y != null) {
println(x * y)
} else {
println("either '$arg1' or '$arg2' is not a number")
}
}
fun main(args: Array<String>) {
printProduct("1", "2")
printProduct("1", "1")
}
Kotlin的空安全设计对于声明可为空的参数,在使用时要进行空判断处理,有两种处理方式,字段后加!!像Java一样抛出空异常,另一种字段后加?可不做处理返回值为null或配合?:做空判断处理
类型检查和自动转型
is关键字用来检查一个表达式是否是某一类型的实例。如果一个不可变的局部变量或属性被检查成一个指定类型,那么没有必要显式转换。
下面的函数用于获取String的长度,但是形参可以是任意类型,所以要判断类型。下面一共有三种写法,代码如下:
fun getStringLength(obj: Any): Int? {
if (obj is String) {
//obj 在该分支下会自动转换成“String”类型
return obj.length
}
//obj 仍然是外部分支的“Any”类型
return null
}
fun getStringLength_1(obj: Any): Int? {
if (obj !is String) return null
//obj 在该分支下被自动转型为“String”类型
return obj.length
}
fun getStringLength_2(obj: Any): Int? {
if (obj is String && obj.length > 0)
return obj.length
return null
}
上面三种写法都是等价的。
可以看到is关键字等同于Java的instanceof关键字,并且更简洁了,因为不需要像Java一样强制转换
循环
for循环
首先看个例子,代码如下:
//for循环 demo
val items = listOf("apple", "banana", "kiwi") //listOf()的返回值是List类型
for (item in items) {
println(item)
}
//List的indices参数表示下标的集合
for (index in items.indices) {
println("item at $index is ${items[index]}")
}
其输出如下:
apple
banana
kiwi
item at 0 is apple
item at 1 is banana
item at 2 is kiwi
for循环可以用于提供了迭代器的任何对象。语法如下:
for(itemn in collection) print(item)
for循环的主体可以是一个语句块。
for(item:Int in ints){
//...
}
当for循环用于数组时,会被编译成基于索引的循环。如果你想使用索引迭代一个数组或list,可以像下面这么做:
for(i in array.indices){
print(array[i])
}
注意,这个“通过范围的迭代”被编译为最优实现,而没有创建额外的对象
或者,你可以使用widthIndex函数,如下
val items = listOf("apple", "banana", "kiwi") //listOf()的返回值是List类型
var index = 0
while (index< items.size) {
println(items[index])
index++
}
while和do..while循环和Java的一样。
while(x>0){
x--
}
do{
val y=retrieveData()
}while(y!=null) //y在这儿是可见的
when表达式
Kotlin去除了switch,但是引入了更为强大的when表达式,例子如下:
fun describe(obj: Any): String =
when (obj) {
1 -> "One"
"Hello" -> "Greeting"
is Long -> "Long"
!is String -> "Not a string"
else -> "Unknown"
}
fun main(args: Array<String>) {
println(describe(1))
println(describe(2L))
println(describe("Hello"))
println(describe(3.2))
}
其结果如下:
One
Long
Greeting
Not a string
when取代了Java、C++中的switch。它最简单的使用形式如下:
when(x){
1 -> print("x==1")
2 -> print("x==2")
else ->{
print("x is neither 1 nor 2")
}
}
when顺序匹配所有分支,直到有分支满足。when既可以用作表达式,也可以用作一个生命。如果用作表达式,那么满足的分支返回的值就是表达式的值。如果用作生命,每个分支的返回值将会被忽略。
如果所有分支都不满足,那么将会走else分支。如果when被用作表达式,那么else分支是强制要求的,除非编译器能够证明所有可能的情况都包含分支条件。
如果很多情况需要以同一种方式处理,那么分支情况可以以逗号进行分割,如下:
fun someCaseSameHandle(obj: Int){
when(obj){
0,1 -> println("obj==0 or obj==1")
else -> println("otherwise")
}
}
我们可以使用任意表达式作为分支的情况,不仅仅是常量值,如下:
when(x){
parseInt(s) -> print("s encodes x")
else -> print("s does not encode x")
}
我们还可以检查一个值是否in或!in在一个范围里或一个集合里
fun rangeWhen(x: Any) {
val validNumbers = listOf("1", "2", "3")
when (x) {
in 1..10 -> println("x is in the range") //位于一个范围
in validNumbers -> println("x is valid") //位于数组中
!in 10..20 -> println("x is outside the range") //在范围之外
else -> println("none of the above")
}
}
fun main(args: Array<String>) {
rangeWhen(1)
rangeWhen("1")
rangeWhen(11)
rangeWhen(30)
}
运行结果如下:
x is in the range
x is valid
none of the above
x is outside the range
when还可以和is或!is联合使用。需要注意的是is带来的自动转型,所以不再需要做额外的类型检查了。代码如下:
fun hasPrefix(x: Any) = when (x) {
is String -> x.startsWith("kotlin")
else -> false
}
when还可以被用来取代if-else链。如果没有参数提供给when,那么分支条件将会默认是布尔表达式,只有在分支为true时,分支才会执行。
fun replaceIfElse(x:Int){
when{
x/2==0 -> println("x is even")
x/2==1 -> println("x is odd")
else -> print("i don't know")
}
}
从上面可以看到when表达式的强大之处:可以与in、!in或集合配合使用来检查范围,可以使用逗号来分隔不同情况的相同处理逻辑,可以与is配合使用,还可以取代if-else等等。
使用范围
在when表达式的介绍中已经涉及了in关键字,in关键字用来检查一个数字是否在一个范围里。
val x=10
val y=9
if(x in 1..y+1){
println("fits in range")
}
还可以使用!in来检查一个数字是否超出了某个范围
val list= listOf("a","b","c")
if(-1 !in 0..list.lastIndex){
println("-1 is out of range")
}
if(list.size !in list.indices){
println("list size is out of valid list indices range too")
}
可以使用for循环在一个范围上迭代:
for(x in 1..5){
print(x)
}
除了在一个范围上以步长为1进行迭代,还可以使用step指定步长,如下:
for (x in 1..10 step 2) {
println(x)
}
for (x in 9 downTo 0 step 3) {
println(x)
}
Range表达式用来定义任何可比较的类型,但是用在基本数值类型时,编译器会有优化。
上面可以看到in后面如果跟的是a..b,那么范围在[a,b]之间,a、b均包含,那么如果想范围在[a,b)之间,那么除了使用a..b-1这种形式,还可以使用如下形式:
for(x in 1 until 10){
print(x)
}
当使用until时,范围为[1,10)。
集合
在一个集合上迭代,代码如下:
for (item in items) {
println(item)
}
使用in操作检查一个集合是否包括某个对象:
when {
"orange" in items -> println("juicy")
"apple" in items -> println("apple is fine too")
}
使用lambda表达式来过滤和映射集合:
fruits
.filter { it.startsWith("a") }
.sortedBy { it }
.map { it.toUpperCase() }
.forEach { println(it) }
代码请见Github