数据类

1
data class Customer(val name: String, val email: String)

Customer提供了以下方法:

  • getters,如果成员变量使用var定义那么还默认提供setters
  • equals()
  • hashCode()
  • toString()
  • copy()
  • component1(), component2() …

这跟Scala的case class基本上差不多,一般在做数据交互/传输时用

函数默认值

1
fun foo(a: Int = 0, b: String = "") { ... }

列表过滤

1
val positives = list.filter { x -> x > 0 }

或者更短一点

1
val positives = list.filter { it > 0 }

默认使用it来接收单个的参数

字符串插值

1
println("Name $name")

对象检查

1
2
3
4
5
when (x) {
    is Foo -> ...
    is Bar -> ...
    else   -> ...
}

非常精简,再也不要写Java那个烦人的instanceof

遍历映射/列表

1
2
3
for ((k, v) in map) {
    println("$k -> $v")
}

k, v分别是map的key和value,是list的index和value

使用范围

1
2
3
4
5
for (i in 1..100) { ... }  // closed range: includes 100
for (i in 1 until 100) { ... } // half-open range: does not include 100
for (x in 2..10 step 2) { ... }
for (x in 10 downTo 1) { ... }
if (x in 1..10) { ... }

只读映射/列表

1
2
val list = listOf("a", "b", "c")
val map = mapOf("a" to 1, "b" to 2, "c" to 3)

如果是集合是不是还有setOf,命名的统一性也是Kotlin的一个亮点,如果你使用过php的话,感觉函数总是记不住。

映射访问

1
2
println(map["key"])
map["key"] = value

懒值(Lazy)

1
2
3
val p: String by lazy {
    // compute the string
}

这段代码在定义的时候是不会执行变量的值的,只有在使用这个变量的时候才会求值

扩展

这是Kotlin一个非常强大的功能,可以对原来已经存在的类添加一系列的新方法,扩展别人的包非常方便

1
2
3
fun String.spaceToCamelCase() { ... }

"Convert this to camelcase".spaceToCamelCase()

单例

做Java是不是会经常被问单例模式是怎么实现的,Kotlin直接使用object来定义,直白得不要不要的,这和Scala也是一样的

1
2
3
object Resource {
    val name = "Name"
}

null值检查

1
2
3
val files = File("Test").listFiles()
println(files?.size)
println(files?.size ?: "empty")

相比Java的if (files != null)优雅太多了。files如果是空值,新手写代码如果不做Null检查,就会碰到最常见的NullException。Kotlin使用问号来检查,并且null值会一值传递到最后。

1
2
val data = ...
val email = data["email"] ?: throw IllegalStateException("Email is missing!")

Kotlin使用?:也是非常的简洁,如果data["email"]有值,直接使用,如果没有就抛出异常。如果想只有在有值的情况下

1
2
3
4
5
val data = ...

data?.let {
    ... // execute this block if not null
}

映射空值检查

1
2
3
val data = ...

val mapped = data?.let { transformData(it) } ?: defaultValueIfDataIsNull

when表达式作为返回值

Kotlin是基于表达式,而不是基于语句的。也就是说任何的语言结构都是有返回值的,这也是和Scala是一样的。

1
2
3
4
5
6
7
8
fun transform(color: String): Int {
    return when (color) {
        "Red" -> 0
        "Green" -> 1
        "Blue" -> 2
        else -> throw IllegalArgumentException("Invalid color param value")
    }
}

这里when是一个表达式,表达式是有值的,如果color是Green,那么这个when的值就是2

try/catch

同样try/catch也是有值的

1
2
3
4
5
6
7
8
9
fun test() {
    val result = try {
        count()
    } catch (e: ArithmeticException) {
        throw IllegalStateException(e)
    }

    // Working with result
}

if

if也是表达式,也是有值的

1
2
3
4
5
6
7
8
9
fun foo(param: Int) {
    val result = if (param == 1) {
        "one"
    } else if (param == 2) {
        "two"
    } else {
        "three"
    }
}

如果上面最后那个else没有写的话,编译是通不过的,如果if作为一个表达式,那么必须覆盖所有的情况。

使用with调用多个方法

这个特性也比较酷,结构跟python的差不多:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
class Turtle {
    fun penDown()
    fun penUp()
    fun turn(degrees: Double)
    fun forward(pixels: Double)
}

val myTurtle = Turtle()
with(myTurtle) { //draw a 100 pix square
    penDown()
    for(i in 1..4) {
        forward(100.0)
        turn(90.0)
    }
    penUp()
}

Java 7的try-with-resources语句

在Java 7的写法如下

1
2
3
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
    return br.readLine();
}

在Kotlin写法更加直观

1
2
3
4
val stream = Files.newInputStream(Paths.get("/some/file.txt"))
stream.buffered().reader().use { reader ->
    println(reader.readText())
}

泛型

1
2
3
4
5
6
//  public final class Gson {
//     ...
//     public <T> T fromJson(JsonElement json, Class<T> classOfT) throws JsonSyntaxException {
//     ...

inline fun <reified T: Any> Gson.fromJson(json): T = this.fromJson(json, T::class.java)

可空布尔类型使用

1
2
3
4
5
6
val b: Boolean? = ...
if (b == true) {
    ...
} else {
    // `b` is false or null
}