Android 开发手册ANDROID DEV

CHAPTER 01语言基础 · LANGUAGE

Kotlin 语言基础

空安全、数据类、密封类、扩展、作用域函数与高阶函数。掌握 Kotlin 的"务实默认",为协程、Compose 与架构打下地基。

开始阅读难度入门约2.5小时
01.1

设计哲学

Kotlin 是 JVM 上的务实语言:与 Java 100% 互操作,默认不可变、默认非空,用简洁语法减少样板代码。

与 Java 的关系

Kotlin 编译成 JVM 字节码,可直接调用全部 Java 库;Android 官方自 2019 年起首选 Kotlin。老项目多为 Java,互操作让迁移逐步进行。

01.2

空安全

类型系统区分 String(非空)与 String?(可空)。编译器强制你处理 null,从根上消灭 NPE。

var name: String? = null
val len = name?.length          // 安全调用,name 为 null 时返回 null
val display = name ?: "匿名"      // 空合并
val forced = name!!.length       // 强制解包,null 时抛 NPE(慎用)

fun greet(input: String?) {
    val n = input ?: return      // Elvis 提前返回
    println("hello $n")
}
!! 是危险信号

与 Swift 的强制解包同理,!! 在 null 时直接崩溃,仅在能 100% 保证非空时使用。

01.3

数据类与密封类

data class 自动生成 equals/hashCode/toString/copy;sealed class 表达受限的类层次,配合 when 可穷尽匹配。

data class User(val id: Long, val name: String)

sealed class UiState {
    data object Loading : UiState()
    data class Success(val data: List) : UiState()
    data class Error(val msg: String) : UiState()
}
fun render(state: UiState) = when(state) {   // 穷尽,无需 else
    is UiState.Loading -> showSpinner()
    is UiState.Success -> showList(state.data)
    is UiState.Error -> showError(state.msg)
}
01.4

扩展函数

无需继承即可给已有类"添加"方法,是 Kotlin 表达力的核心。Android 大量 API 通过扩展增强。

fun String.truncate(max: Int) =
    if (length <= max) this else take(max) + "…"

"Hello World".truncate(5)   // "Hello…"

// 扩展属性
val Context.screenWidth: Int
    get() = resources.displayMetrics.widthPixels
01.5

高阶函数与 lambda

函数可作为参数与返回值。lambda 尾部调用可写在括号外,是 Kotlin DSL(如 Compose、Gradle Kotlin DSL)的基础。

fun <T> List<T>.filterIndexed(pred: (Int, T) -> Boolean): List<T> = ...

list.filter { it > 0 }                 // 单参用 it
list.fold(0) { acc, x -> acc + x }     // 多参显式命名
01.6

作用域函数

let/run/with/apply/also 在对象上下文中执行代码块,区别在于"返回什么、用谁做 this/it"。

函数上下文返回典型用途
letitlambda 结果空安全检查、链式转换
applythis对象自身对象初始化配置
alsoit对象自身副作用(日志、校验)
runthislambda 结果对象上计算一个值
01.7

属性与懒加载

val 不可变、var 可变;by lazy 延时到首次访问才计算,适合昂贵初始化。

val heavy: Database by lazy {
    Database.connect()   // 首次访问时才执行
}
val name: String get() = "computed"   // 自定义 getter
01.8

常见陷阱

val 一定不可变吗?

val 只保证引用不可变,若它指向可变对象(如 val list = mutableListOf()),列表内容仍可变。需要真正不可变用 listOf()。

when 没写 else 会怎样?

对密封类 when 不要求 else(编译器知穷尽);对普通类型则必须 else 否则漏分支编译报错,这是类型安全的保障。

01.9

实战练习

延伸资源