Android函数式编程代码规范文档

前言

为统一团队Android函数式编程编码风格,降低维护成本,规避性能与内存风险,结合Kotlin语言特性及Android工程化实践,制定本规范。本规范适用于团队所有Android开发人员,涵盖函数式编程的命名、语法、使用场景、内存安全等核心内容,需严格遵循并纳入CodeReview检查项。

本规范参考Android代码风格指南的核心原则,兼顾可读性、可维护性与性能,聚焦函数式编程在Android场景的落地细节,避免理论化,突出实用性与可执行性。

一、通用原则

  1. 函数式编程核心:优先遵循「不可变性、纯函数、无副作用」三大特性,平衡代码简洁性与可维护性,拒绝为炫技过度抽象。
  2. 场景适配优先:仅在适合函数式编程的场景使用(数据处理、状态计算等),规避生命周期敏感、高频性能等不适配场景。
  3. 可读性至上:代码编写需兼顾新人理解成本,避免过度嵌套与晦涩语法,注释清晰、命名规范。
  4. 性能底线:在保证代码简洁的前提下,规避函数式编程的性能开销,必要时回退到命令式编程。

二、命名规范(强制执行)

2.1 高阶函数命名

  • 命名需明确体现"操作意图",后缀建议使用With、Run、onXxx,直观反映函数功能。
  • 示例:requestPermissionWithRetry(带重试的权限申请)、onUserClick(用户点击回调)、fetchDataWithDebounce(带防抖的数据请求)。
  • 禁止:命名模糊(如doFunction、handleData)、无意义缩写(如funcWithRetry缩写为funcWR)。

2.2 纯函数命名

  • 命名需明确"输入-输出"关系,采用"名词/动词+结果"的格式,清晰反映函数的计算逻辑。
  • 示例:formatTime(时间格式化)、filterAdultUser(筛选成年用户)、validatePhoneNumber(校验手机号)、mergeTwoList(合并两个列表)。
  • 禁止:命名与功能不符(如明明是筛选函数,却命名为getUserList)。

2.3 变量与常量命名

  • 不可变变量:全部使用val修饰,命名遵循Kotlin驼峰命名法,首字母小写。
  • 可变变量:仅在必要时使用var修饰,命名需标注原因(添加注释),禁止滥用var。
  • 常量:使用const或val修饰(顶层常量),全部大写,单词间用下划线分隔,如MAX_DATA_SIZE、PERMISSION_REQUEST_CODE。
  • 禁止:用var修饰无需修改的变量,常量命名使用驼峰命名法。

2.4 类与接口命名

  • 函数式相关工具类:命名以Util结尾,首字母大写,如FunctionalUtil、FlowUtil。
  • 函数式接口:命名以Interface结尾或体现接口功能,首字母大写,如DataTransformInterface、PermissionCallbackInterface。

三、语法使用规范(强制执行)

3.1 标准函数使用

  • 优先使用Kotlin标准函数(let/run/with/also/takeIf),避免自定义冗余的高阶函数。
  • 场景适配:
    • let:用于空安全判断、对象链式调用,如user?.let { it.name }。
    • run:用于对象内部操作,返回操作结果,如user.run { "姓名:name,年龄:name,年龄:name,年龄:age" }。
    • with:用于对同一对象进行多个操作,无需重复写对象名,如with(user) { name + age }。
    • also:用于对象附加操作(不改变对象本身),返回对象本身,如user.also { it.log() }。
    • takeIf:用于条件判断,满足条件返回对象,否则返回null,如user.takeIf { it.age >= 18 }。
  • 禁止:滥用标准函数(如简单的空判断用let替代if-else)、混淆标准函数的使用场景。

3.2 Lambda使用规范

  • 嵌套限制:Lambda嵌套不超过2层,超过2层需拆分独立函数,保证可读性。
    • 正确:将内层Lambda抽为独立函数,再通过函数引用调用。
    • 错误:Lambda内部嵌套Lambda,且嵌套层数≥3。
  • 参数简化:单个参数的Lambda,优先使用it指代;多个参数的Lambda,需明确参数名,不建议用_省略(除非参数无需使用)。
    • 正确:list.filter { it.age >= 18 }、list.map { user -> user.name }。
    • 错误:list.map { _ -> it.name }(参数名模糊)、list.filter { u -> u.age >= 18 }(单个参数无需自定义参数名)。
  • 代码长度:单个Lambda代码长度不超过5行,超过5行需拆分独立函数。

3.3 流式操作规范

  • 集合处理:所有流式操作(map/filter/flatMap/groupBy等)必须使用asSequence()优化,避免创建中间集合,减少内存开销。
    • 正确:list.asSequence().filter { it.age >= 18 }.map { it.name }.toList()。
    • 错误:list.filter { it.age >= 18 }.map { it.name }(未使用asSequence())。
  • 链式限制:流式操作的链式调用不超过5个操作符,超过5个需拆分,每个操作符单独换行并添加注释。
    • 正确:
      list.asSequence()
      .filter { it.age >= 18 } // 筛选成年用户
      .map { it.name } // 提取用户姓名
      .distinct() // 去重
      .sorted() // 按字母排序
      .toList()
    • 错误:list.asSequence().filter { it.age >= 18 }.map { it.name }.distinct().sorted().take(10).toList()(链式过长,无注释)。

3.4 纯函数编写规范

  • 无副作用:纯函数内部不修改外部变量、不执行IO操作(SP写入、数据库更新、网络请求)、不操作View。
  • 输入决定输出:相同的输入必须返回相同的输出,不依赖外部状态。
  • 禁止:在纯函数中使用全局变量、静态变量,或执行有副作用的操作。

四、场景使用规范(强制执行)

4.1 优先使用函数式编程的场景

  1. 数据转换与数据流处理:网络请求结果解析、JSON→Model映射、列表过滤/排序/分组、Flow/RxJava流式处理、Room查询结果格式化。
  2. 回调简化与通用逻辑封装:View点击事件、RecyclerView item点击事件简化,高阶函数封装权限申请、重试、延时等通用逻辑。
  3. UI状态计算与映射:Compose中UI状态推导、页面状态联动、网络请求状态转换(加载中/成功/失败)。
  4. 纯业务逻辑与工具类方法:数据校验、数据格式化、字符串/集合工具类方法。
  5. 并发安全场景:多线程数据传递、并发计算(利用不可变性避免线程竞争)。

4.2 禁止/谨慎使用函数式编程的场景

  1. 生命周期敏感的UI操作:Activity/Fragment生命周期相关操作、View创建、Dialog/Toast弹出。
  2. 高频性能场景:RecyclerView快速滑动(onBindViewHolder高频调用)、动画onDraw/onMeasure、触摸事件onTouch。
  3. 强副作用逻辑:连续修改外部变量、执行SP/文件写入、数据库更新等IO操作。
  4. 维护成本高的场景:团队新手过多的老项目,不建议全量使用函数式编程,仅在新代码中逐步适配。
  5. 内存敏感模块:图片加载、大文件处理、视频处理(需精准控制内存,避免函数式产生的临时对象)。

五、禁止行为(红线,不可触碰)

  1. 禁止在函数式代码中操作View(如setText、showDialog、setVisibility等)。
  2. 禁止在函数式代码中捕获生命周期对象(Activity、Fragment、Context),避免内存泄漏。
  3. 禁止在主线程高频调用函数式操作(如RecyclerView onBindViewHolder、动画绘制、触摸事件监听)。
  4. 禁止为了炫技而过度抽象(如用函数式封装简单的if-else逻辑,导致代码可读性下降)。
  5. 禁止在函数式代码中执行强副作用操作(SP写入、数据库更新、网络请求、修改外部变量)。
  6. 禁止Lambda嵌套超过2层、流式操作链式调用超过5个且无注释。
  7. 禁止用var修饰不可变变量,禁止纯函数依赖外部状态。
  8. 禁止使用全局高阶函数(优先使用局部高阶函数或类内成员函数,减少内存占用)。

六、内存与安全规范(强制执行)

6.1 闭包使用规范

  • 禁止闭包捕获Context、Activity、Fragment等生命周期对象,如需使用,必须用WeakReference包裹,避免内存泄漏。
    • 正确:val weakContext = WeakReference(context),weakContext.get()?.let { ... }。
    • 错误:闭包直接捕获context,且未及时释放引用。
  • 闭包内部尽量使用局部变量,避免捕获外部变量(减少内存持有)。

6.2 不可变性规范

  • 所有Model类、数据实体,一律使用data class + val修饰,禁止使用var;修改数据时,通过copy方法创建新对象。
    • 正确:data class User(val name: String, val age: Int),val newUser = user.copy(age = 20)。
    • 错误:data class User(var name: String, var age: Int)(使用var修饰属性)。
  • 集合优先使用不可变集合(listOf、setOf、mapOf),禁止使用可变集合(mutableListOf等)传递数据,避免外部修改。

6.3 内存优化规范

  • 避免函数式操作产生大量临时对象,尤其是大数据量场景(数据量≥1万条),需使用Sequence优化或回退到普通循环。
  • 基本类型优先使用Kotlin原生集合(IntArray、LongArray等),、,避免自动装箱产生的内存开销。
  • Compose中,函数式计算结果需用remember、rememberUpdatedState等API缓存,避免重组时重复计算。

七、CodeReview检查项(强制执行)

  1. 命名规范:高阶函数、纯函数、变量、常量命名是否符合本规范。
  2. 语法规范:Lambda嵌套是否≤2层,流式操作是否使用asSequence(),链式调用是否≤5个且有注释。
  3. 场景规范:是否在不适配场景使用函数式编程(如生命周期UI操作、高频性能场景)。
  4. 禁止行为:是否存在红线行为(如捕获生命周期对象、操作View、强副作用等)。
  5. 内存安全:闭包使用是否规范,不可变性是否符合要求,是否存在内存泄漏风险。
  6. 可读性:代码是否清晰,注释是否完整,复杂逻辑是否拆分独立函数。
相关推荐
安卓蓝牙Vincent2 小时前
Android BLE SDK 设计手册(一):一次参数改动,让我重新设计了整套架构
android·架构
angerdream2 小时前
Android手把手编写儿童手机远程监控App之广播开机自启动
android·android studio
su_ym81102 小时前
Android SELinux
android·selinux
阿巴斯甜2 小时前
Android中项目架构:
android
程序员陆业聪4 小时前
线上监控与防劣化:让启动优化成果不再回退 | Android启动优化系列(五·完结)
android
程序员陆业聪4 小时前
首帧渲染优化:从白屏到内容可见的最后一公里
android
AI玫瑰助手4 小时前
Python基础:字符串的常用内置方法(查找替换分割)
android·开发语言·python
xiangxiongfly9155 小时前
Android 使用WebSocket通信
android·websocket·网络协议·okhttp
su_ym81106 小时前
Android属性系统
android·framework·property