先提个问题

Android程序员为什么要学Kotlin?

  1. Java不争气。在1.5时代Java或许还能和C#谈笑风生,而现在C#不知道比Java高明到哪里去了。虽然Java8中也加入了闭包等有用的特性,但Android又不支持……
  2. RxJava。想象这样一个需求:用户连续点击某个区域10次且每次间隔不超过500毫秒,则触发一个彩蛋。
    实现这个需求很容易,但代码会很混乱。我们得自己控制计时器,保存时间戳,可能还会有令人讨厌的空接口。如果用RxJava来做,几行代码就能搞定。如果再配合Kotlin的函数式编程,简直不能更爽~
    关于RxJava的使用,网上已经有很多了。我有空了可能也会写一些。
  3. 如果你尝试了Android Databinding,有没有发现External Libraries里面多了kotlin-runtime和kotlin-stdlib?
    Google内部正是用Kotlin开发的Databinding。虽然短期内Kotlin还不太可能成为Android官方开发语言,但至少这是个好的迹象。

为什么是Kotlin?

现在替代Java的选择有很多,Scala、Groovy都能写Android,甚至微软最新发布的Visual Studio都能进来插一脚,为什么要选Kotlin呢?
这又是另一个很大的话题了。请参看大神Jake Wharton的这篇文章(要翻墙)。

那么进入正题。我的学习步骤基本是按照官方的Reference来,所以可能写着写着就成了翻译官方文档了……哈哈哈哈

Function

最开始学C的时候,我们会说为了实现XXX写个函数(Function),学Java就变成了写个方法(Method),现在Kotlin又变成函数了……
所以我后面提到Java的时候会说Method,提到Kotlin的时候会说Function,其实都是一个意思~

先看下Java中的写法

1
2
3
int sum(int a, int b) {
return a + b;
}

然后是Kotlin

1
2
3
fun sum(a: Int, b: Int): Int {
return a + b
}

区别:

  1. 用fun开头
  2. 数据类型写在后面
  3. 结尾不用写分号

这语法让我想起了Action Script,写惯了Java再来写Kotlin总觉得有些别扭……

如果想简洁一点可以这样写在一行里,并且返回值类型可以是隐式(inferred)的。不过我个人不太喜欢这样写。

1
fun sum(a: Int, b: Int) = a + b

如果是public function就必须显式的标明返回类型

1
public fun sum(a: Int, b: Int): Int = a + b

没有返回值则用Unit关键字

1
2
3
fun printSum(a: Int, b: Int): Unit {
print(a + b)
}

即使函数是public的,Unit也可以省略掉

1
2
3
public fun printSum(a: Int, b: Int) {
print(a + b)
}

local variables

只读变量(read-only)用val定义

1
2
3
4
val a: Int = 1
val b = 1 // 如果赋了初始值值,可以省略数据类型
val c: Int // 否则需要指定类型
c = 1

可变变量(mutable)用var定义

1
2
var x = 5
x += 1

string templates

${}包住变量就行了,这比Java中的String.valueof方便多了

1
2
val a = 1
print("Value of a: ${a}"}

conditional expressions

看起来有点像三元表达式,但可读性更强

1
fun max(a: Int, b: Int) = if (a > b) a else b

nullable values

写java的同学一定受够了NullPointerException吧。Kotlin与Java很大不同的一点就是显示的标明了value是否可能为空。
如果可能为空,则用?注明

1
var x: Int?

先知道有这么回事就行了,后面的章节会详细说明。

type checks & automatic casts

和C#一样,用is操作符来判断变量的类型

1
2
3
4
5
6
fun getStringLength(obj: Any): Int? {
if (obj is String) {
return obj.length // 注意这里obj已经自动转成String类型了,所以可以调用length方法
}
return null // 这里obj依然是Any类型
}

loop

和Java相比是把冒号改成了in

1
2
3
4
fun main(args: Array<String>) {
for (arg in args)
print(arg)
}

while loop

和Java基本一样

1
2
3
4
5
fun main(args: Array<String>) { 
var i = 0
while (i < args.size())
print(args[i++])
}

when expression

when可以类比Java中的switch case,但是更加强大,可以接受各种操作符

1
2
3
4
5
6
7
8
9
fun cases(obj: Any) { 
when (obj) {
1 -> print("One")
"Hello" -> print("Greeting")
is Long -> print("Long")
!is String -> print("Not a string")
else -> print("Unknow")
}
}

ranges

in操作符太好用了,我就不贴对应的Java代码了,因为想想就觉得麻烦……

1
2
3
4
5
6
7
8
if (x in 1..y-1) 
print("OK")

if (x !in 0..array.lastIndex)
print("Out")

for (x in 1..5)
print(x)

collections

collections配合in使用很方便

1
2
if (text in names) // 这里调用了names.contains(text) 
print("Yes")

如果配合函数式编程和Lambdas表达式就不能更爽……

1
2
3
4
names filter { it.startsWith("A") } 
sortBy { it }
map { it.toUpperCase() }
forEach { print(it) }

注意这里函数前面没有小圆点(.),这个大概是特有的简写,后面再慢慢学吧~