跳转到正文
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 面向对象与委托模式
YGJoon 的头像

YGJoon

记录 Flutter、Web 与原生移动端工程实践。更多背景见关于页,源码与项目见GitHub。