跳转到正文
YGJoon 技术博客

Android Kotlin 函数式编程与控制流

发布于:
·1.0k 字 · 约 3 分钟·作者:
Kotlin 函数式写法在业务层的落地:let/run/apply 选型、高阶函数封装 Repository、ViewModel 状态转换,写出更短的业务逻辑。
Android Kotlin 函数式编程与控制流文章封面
目录

控制流语法回顾

when 表达式

fun mapHttpCode(code: Int): String = when (code) {
    in 200..299 -> "Success"
    401, 403 -> "Unauthorized"
    in 500..599 -> "Server Error"
    else -> "Unknown"
}

if 表达式

val indicator = if (isDebug) "DEBUG" else "RELEASE"

循环

for (index in items.indices) {
    println("index=$index value=${items[index]}")
}

items.forEachIndexed { index, value ->
    println("index=$index value=$value")
}

函数式编程核心概念

1. 高阶函数与 Lambda

fun <T> List<T>.customFilter(predicate: (T) -> Boolean): List<T> {
    val result = mutableListOf<T>()
    for (item in this) {
        if (predicate(item)) {
            result += item
        }
    }
    return result
}

val activeUsers = users.customFilter { it.isActive }

2. 匿名函数与命名参数

val comparator = fun(a: Int, b: Int): Int = a - b
val sorted = listOf(3, 1, 2).sortedWith { a, b -> comparator(a, b) }

3. 扩展函数

fun TextView.setSafeClickListener(interval: Long = 600, action: (View) -> Unit) {
    var lastClick = 0L
    setOnClickListener { view ->
        val now = SystemClock.uptimeMillis()
        if (now - lastClick > interval) {
            lastClick = now
            action(view)
        }
    }
}

button.setSafeClickListener { navigateToDetail() }

标准库函数家族

函数返回值场景
letlambda 结果对可空对象链式调用
runlambda 结果在对象作用域内初始化/配置
apply原对象初始化 Builder/自定义 View
also原对象链式副作用,如日志、埋点
withlambda 结果需要显式传入对象
val dialog = MaterialAlertDialogBuilder(context).run {
    setTitle("提示")
    setMessage("确定删除?")
    setPositiveButton("删除", null)
    create()
}.apply {
    setCanceledOnTouchOutside(false)
}

Android 业务实战

1. Repository 函数式封装

suspend fun <T> safeRequest(block: suspend () -> T): Result<T> {
    return try {
        Result.success(block())
    } catch (e: Throwable) {
        Result.failure(e)
    }
}

suspend fun loadUserProfile(id: Long): Result<User> = safeRequest {
    apiService.getUser(id)
}

2. ViewModel 状态转换

val uiState: StateFlow<HomeUiState> = repository.state
    .map { data -> HomeUiState.Success(data) }
    .catch { emit(HomeUiState.Error(it)) }
    .stateIn(viewModelScope, SharingStarted.Lazily, HomeUiState.Loading)

3. DSL 构建器

inline fun buildLinearLayout(context: Context, block: LinearLayout.() -> Unit): LinearLayout {
    return LinearLayout(context).apply {
        orientation = LinearLayout.VERTICAL
        block()
    }
}

val layout = buildLinearLayout(context) {
    addView(TextView(context).apply { text = "Title" })
    addView(Button(context).apply { text = "Click" })
}

性能与可读性建议

实战案例:let/apply/run 别背,记”返回值”

Kotlin 的作用域函数(let、run、with、apply、also)是新人噩梦,五个长得像,行为各不同。我用的记忆法只记两件事:it 还是 this,返回什么:

函数上下文对象返回值
letitlambda 结果
runthislambda 结果
applythis对象本身
alsoit对象本身
withthislambda 结果

实战里 90% 的场景只用两个:?.let { }(空判 + 转换,返回转换结果)、apply { }(Builder 式初始化,返回对象本身)。also 专门干”顺手打个日志”这种副作用,with 和 run 几乎可以互相替代。

Dart 没有这些,但有 cascade ..(≈ apply)和 ?.(≈ ?.let 的穷人版)。我在 Dart 里写 config..baudRate = 9600..bits = 8,Kotlin 侧就是 config.apply { baudRate = 9600; bits = 8 }。理解了这个映射,五个函数一下就通了。

忠告:别在团队里秀 let 嵌套三层——可读性是第一生产力。链式超过两层就拆成变量,review 的人会感谢你。

参考:Kotlin 官方文档《Scope functions》

总结

  1. Kotlin 的函数式特性可让 Android 业务逻辑更加简洁,但需注意合理使用以避免可读性下降。
  2. 标准库 scope functions 能提升对象初始化与空安全处理效率。
  3. 函数式思想适用于 Repository 封装、状态映射、DSL Builder 等场景。

下一篇将聚焦 Kotlin 的面向对象特性与委托模式,为构建复杂模块奠定基础。


分享这篇文章:


相关文章

上一篇
Android Kotlin 数据类型与空安全
下一篇
Android Kotlin 面向对象与委托模式