 
        
        Taiwan Kotlin User Group 的網站,在台灣推廣 Kotlin 程式語言,舉辦相關活動。如果對 Kotlin 有興趣,想要多瞭解一些,歡迎來我們的社群一起聚會!
下面列出一些常見的 Kotlin 慣用寫法
建立 DTO
(或稱 POJO,Plain Old Java Object)
data class Customer(val name: String, val email: String)
建立 Customer 類別
並包含下列函數:
var 會包含 setterequals()hashCode()toString()copy()component1()、component2()⋯⋯fun foo(a: Int = 0, b: String = "") { ... }
val positives = list.filter { x -> x > 0 }
更短的寫法
val positives = list.filter { it > 0 }
if ("john@example.com" in emailsList) { ... }
if ("jane@example.com" !in emailsList) { ... }
println("Name $name")
when (x) {
    is Foo -> ...
    is Bar -> ...
    else   -> ...
}
val list = listOf("a", "b", "c")
val map = mapOf("a" to 1, "b" to 2, "c" to 3)
println(map["key"])
map["key"] = value
for ((k, v) in map) {
    println("$k -> $v")
}
也可用來遍歷元素為 Pair 型態的 list
val list = listOf(  
    Pair("name", "Alice"),   
    Pair("age", 18)  
)  
for ((k, v) in list) {  
    println("$k -> $v")  
}
k 和 v 都可以換成可讀性更高的名稱
像是 name 和 age
從 1 到 100
for (i in 1..100) { ... }
從 1 到 99,不包含 100
for (i in 1 until 100) { ... }
2 4 6 8 10
for (x in 2..10 step 2) { ... }
從 10 到 1
for (x in 10 downTo 1) { ... }
if (x in 1..10) { ... }
val p: String by lazy {
    // compute the string
}
可在原生型態上增添新函數
fun String.spaceToCamelCase() { ... }
"Convert this to camelcase".spaceToCamelCase()
建立單例(singleton)
object Resource {
    val name = "Name"
}
abstract class MyAbstractClass {
    abstract fun doSomething()
    abstract fun sleep()
}
fun main() {
    val myObject = object : MyAbstractClass() {
        override fun doSomething() {
            // ...
        }
        override fun sleep() { // ...
        }
    }
    myObject.doSomething()
}
如果 files 不為 null
印出 files.size
println(files?.size)
如果 files 不為 null
印出 files.size
如果 files 為 null
印出 "empty"
println(files?.size ?: "empty")
null 執行特定行為如果 values["email"] 為 null
拋出例外 IllegalStateException("Email is missing!")
val email = values["email"] 
    ?: throw IllegalStateException("Email is missing!")
emails 為 List<String>
如果集合為空,則取出預設物件("")
val mainEmail = emails.firstOrNull() ?: ""
null 時執行value?.let {
    // 變數不為 null 時執行此段落
}
假設 value 型態是 Int?
mapped 轉換成 List<Int>
如果 value 是 null
把 mapped 設置為 listOf(0)
val mapped = value?.let { listOf(it) } ?: listOf(0)
fun transform(color: String): Int {
    return when (color) {
        "Red" -> 0
        "Green" -> 1
        "Blue" -> 2
        else -> 
            throw IllegalArgumentException("Invalid color")
    }
}
在 Kotlin try-catch 是表達式
回傳結果可以直接寫入變數
fun test() {
    val result = try {
        count()
    } catch (e: ArithmeticException) {
        throw IllegalStateException(e)
    }
    // Working with result
}
在 Kotlin if 是表達式
回傳結果可以直接寫入變數
fun foo(param: Int) {
    val result = if (param == 1) {
        "one"
    } else if (param == 2) {
        "two"
    } else {
        "three"
    }
}
Unit 函數的生成器模式fill() 的回傳值是 Unit
(對等其他語言的回傳 void)
下面建立大小為 size
全部值為 -1 的 IntArray
fun arrayOfMinusOnes(size: Int): IntArray {
    return IntArray(size).apply { fill(-1) }
}
fun theAnswer() = 42
上面等同於
fun theAnswer(): Int {
    return 42
}
單一表達式函數搭配上其他慣用寫法
可以寫出更簡潔的程式
例如搭配上 when 表達式
fun transform(color: String): Int = when (color) {
    "Red" -> 0
    "Green" -> 1
    "Blue" -> 2
    else -> 
        throw IllegalArgumentException("Invalid color")
}
利用 with()
class Turtle {
    fun penDown()
    fun penUp()
    fun turn(degrees: Double)
    fun forward(pixels: Double)
}
val myTurtle = Turtle()
// 畫出大小 100 畫素的正方形
with(myTurtle) { 
    penDown()
    for (i in 1..4) {
        forward(100.0)
        turn(90.0)
    }
    penUp()
}
利用 apply()
val myRectangle = Rectangle().apply {
    length = 4
    breadth = 5
    color = 0xFAFAFA
}
在處理沒有出現在建構子內的屬性時
非常方便的寫法
val stream = Files.newInputStream(
        Paths.get("/some/file.txt")
    )
stream.buffered().reader().use { reader ->
    println(reader.readText())
}
假設 Gson 和 Gson.fromJson()
的宣告為
public final class Gson {
    // ...
    public <T> T fromJson(JsonElement json, Class<T> classOfT) 
        throws JsonSyntaxException {
    // ...
使用時我們會需要 Class<T> 的資訊
利用 inline fun 和 reified 關鍵字
我們可以讓泛型函數內
取得泛型參數的類別資訊
inline fun <reified T: Any> Gson.fromJson(json: JsonElement): T =
    this.fromJson(json, T::class.java)
這邊 <T> 型態是 Any
可以放入任意類別
使用起來非常簡潔
Gson.fromJson<MyDataClass>(json)
null 的 Booleanval b: Boolean? = ...
if (b == true) {
    ...
} else {
    // `b` 為 false 或 null
}
a = b.also { b = a }
利用 TODO() 函數
TODO() 執行時會拋出 NotImplementedError 中斷程式
TODO() 的回傳值是 Nothing
所以可以無視函數設定的回傳值
TODO()內可以宣告理由
fun calcTaxes(): BigDecimal = TODO("等會計部門回需求")
IntelliJ IDEA 的 kotlin plugin 認得 TODO()
並會自動將內容放在 TODO 工具視窗內
想了解更多嗎?
可以看看 Kotlin 語法特色
或加入 kotlin.tips 的 Kotlin 讀書會 !