Android 開發者的 Kotlin 基礎語法

Kotlin 設計的初衷就是為了解決 Java 的痛點。在 Android 開發中,有幾個 Kotlin 特性是我們每天都會用到的。掌握這些語法,能讓你的程式碼更簡潔、更安全。

Null Safety (空值安全)

告別 NullPointerException!Kotlin 預設變數是不可為空 (Non-nullable) 的。

// ❌ 編譯錯誤:name 不能是 null
// var name: String = null

// ✅ 正確:加上 ? 表示可為空
var name: String? = null

// 安全呼叫 (Safe Call)
val length = name?.length // 如果 name 是 null,length 就會是 null,不會崩潰

// Elvis Operator (?:)
val length2 = name?.length ?: 0 // 如果是 null,就給預設值 0

Lambda 與高階函式

在 Jetpack Compose 中,Lambda 表達式無處不在。特別是Trailing Lambda Syntax(如果最後一個參數是函式,可以移到括號外)。

// 定義一個接受函式作為參數的函式
fun setOnClickListener(listener: () -> Unit) { ... }

// 呼叫方式 1: 標準寫法
setOnClickListener({ println("Clicked") })

// 呼叫方式 2: Trailing Lambda (推薦)
setOnClickListener {
    println("Clicked")
}

這也是為什麼 Compose 的排版程式碼看起來像這樣:

Column {
    Text("Hello")
    Button(onClick = { /* Do something */ }) {
        Text("Click Me") // Button 的最後一個參數也是 Lambda (content)
    }
}

Extension Functions (擴充函式)

不需要繼承類別,就能為現有的類別增加新功能。

// 為 String 類別增加一個函式
fun String.addExclamation(): String {
    return this + "!"
}

val text = "Hello"
println(text.addExclamation()) // 輸出 "Hello!"

這在 Android 中非常實用,例如簡化 Toast 的顯示:

fun Context.showToast(message: String) {
    Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}

// 在 Activity 中直接呼叫
showToast("歡迎回來!")

Data Class (資料類別)

用來儲存資料的類別,編譯器會自動生成 toString(), equals(), copy() 等方法。

data class User(val name: String, val age: Int)

val user1 = User("Alice", 20)
val user2 = user1.copy(age = 21) // 複製並修改部分屬性

println(user1) // 輸出 User(name=Alice, age=20)

Compose 的狀態 (State) 更新常用到 copy()

Scope Functions (作用域函式)

let, run, with, apply, also 是 Kotlin 的五大作用域函式,用來讓程式碼更優雅。

  • let:通常配合 ?. 用來處理非空值。

    name?.let { 
        // 這裡的 it 是 name (且保證不為 null)
        println("User name is $it") 
    }
    
  • apply:設定物件屬性,回傳物件本身。常用於初始化。

    val intent = Intent().apply {
        action = Intent.ACTION_VIEW
        data = Uri.parse("https://www.google.com")
    }
    

Property Delegates (屬性委派)

將屬性的 get/set 邏輯委派給另一個物件處理。最著名的例子就是 lazy

// 只有在第一次使用時才會執行初始化程式碼
val database by lazy {
    Database.getInstance()
}

在 Compose 中,我們使用 by remember 來委派狀態:

var count by remember { mutableStateOf(0) }
// count 可以直接像 Int 一樣讀寫,不需要 .value

熟悉這些語法,你閱讀 Android 官方文件或開源專案時會感到更加輕鬆。