针对有 Java 背景的开发者,学习 Kotlin 的核心在于“语法差异”和“思维转换”。
第一部分: 消除冗余
变量与分支
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| const val MAX_COUNT = 100
fun main() { var count = 0
var name:String
count += 1
name = "str($count)"
println("count is $count name is $name")
count = if (name.length > 10) 10 else name.length count = if (name.length in 0..10) name.length else 10
val item = "Apple" val price = when(item) { "Apple" -> 2.99 "Banana" -> 4.99
else -> 0.99 } }
|
空安全
1 2 3 4 5 6 7 8 9 10 11 12
| fun nullF() { var v1: String? = null val count: Int? = v1?.count()
val v2: String = v1 ?: "base"
v1!!.count() }
|
函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| private fun add(item: Int, delta: Double = 3.0) : Double { return item + delta }
public fun doChange(base: Int): Unit { val v1 = add(base, 1.2) val v2 = add(base) todo() }
private fun todo(): Nothing { throw NotImplementedError() }
private fun g1(name: String = "GGBoy", age: Int = 22): Boolean { return false }
private fun g2() { g1(age=12, name="Bob") }
private fun f1() { val count = "GG Boy".count { s -> s == 'G' }
val welcomeF: (String) -> String = { "Welcome $it" }
val addF = {name: String, age: Double -> "welcome $name with age $age"}
val g = {b: String, f: (String, Double) -> String -> b +f("GG Boy", 22.3) }
g("Tag: ") { n, i -> "n $n + $i" } }
|
Kotlin的文件级函数对应为Java的类静态方法. 类名对应文件名.
内联函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| private inline fun g(b: String, f: (String, Double) -> String) { b +f("GG Boy", 22.3) }
private fun f2() { println("Start") g("Tag: ") { n, i -> "n $n + $i" } println("end") }
private static final void f2() { String b$iv = "Start"; System.out.println(b$iv); b$iv = "Tag: "; int $i$f$g = false; StringBuilder var10000 = (new StringBuilder()).append(b$iv); double i = 22.3; String n = "GG Boy"; StringBuilder var6 = var10000; int var5 = false; String var7 = "n " + n + " + " + i; var6.append(var7).toString(); b$iv = "end"; System.out.println(b$iv); }
|
定义类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
|
class Player(name: String, hp: Double) { val name = name get() = "User: $field"
var hp: Int = (hp*100).toInt() get() = field * 100 set(value) { field = value / 100 }
private var pName = "private"
var pName2 = "private" private set(v) { field = v + "\n" }
val rolledValue get() = (1..6).shuffled().first()
lateinit var aligment: String
val hometown = lazy { File("town.txt").readText().split("\n").shuffled().first() }
constructor(name: String) : this(name, 100.0)
init { require(hp > 0) { "hp must greater than zero" } }
fun greetStr(name: String) = "greet, $name" }
|
继承与多态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| open class Room(name: String) { open fun load() = "Nothing..." }
open class TownSquare: Room("Town Square") { final override fun load() = "load Town" }
fun f2(t: Any): String { val className = when(t) { is TownSquare -> "Town" is Room -> "Room" else -> "Unknown" } return className }
|
对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| object Game { init { println("Game Init") }
fun play() { println("play") } }
val temp = object : Room("Temp") { override fun load()= "load Temp" }
class GameMap {
companion object { private const val MAP_PATH = "map.txt" fun load() = File(MAP_PATH).readBytes() } }
data class Coordinate(val x: Int, val y: Int)
enum class Direction { NORTH, EAST, SOUTH, WEST, }
|
接口与抽象类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| interface Bird { val rolledValue get() = (1..6).shuffled().first() fun Fly() }
abstract class AbsBird() : Bird { override fun Fly() { println("fly") } abstract fun DoSome() }
|
标准函数
| 函数 |
接收者 (this) |
参数 (it) |
返回值 |
主要用途 |
| apply |
对象本身 |
无 |
对象本身 |
对象初始化配置 |
| let |
无 |
对象本身 |
lambda最后一行 |
非空转换、作用域变换 |
| run |
对象本身 |
无 |
lambda最后一行 |
对象计算、作用域变换 |
| also |
无 |
对象本身 |
对象本身 |
附加操作、副作用 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| fun stdF(i: String?) { val file = File("a.txt").apply { setReadable(true) setWritable(true) }
val firstItemSquare = listOf(1, 2, 3).first().let { it*it }
val welcome = i?.let { "welcome $it" } ?: "welcome user"
val containsGGBoy = File("a.txt").run { readText().contains("GG Boy") }
val file2 = File("a.txt").also { println(it.name) }
val file3 = File("b.txt").takeIf { it.canRead() && it.canWrite() }?.readText() }
|
扩展
1 2 3 4 5 6
| fun String.addTag(tag: String) = "$this(Tag: $tag)"
val String.numVowels get() = count{ "aeiouy".contains(it)}
|
扩展函数和属性可以用private修饰, 使得该扩展仅在当前文件内有效.
泛型扩展
1 2 3 4 5 6 7 8 9 10 11 12 13
|
public inline fun <T> T.apply(block: T.() -> Unit): T { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } block() return this }
|