前言
为统一团队Android函数式编程编码风格,降低维护成本,规避性能与内存风险,结合Kotlin语言特性及Android工程化实践,制定本规范。本规范适用于团队所有Android开发人员,涵盖函数式编程的命名、语法、使用场景、内存安全等核心内容,需严格遵循并纳入CodeReview检查项。
本规范参考Android代码风格指南的核心原则,兼顾可读性、可维护性与性能,聚焦函数式编程在Android场景的落地细节,避免理论化,突出实用性与可执行性。
一、通用原则
- 函数式编程核心:优先遵循「不可变性、纯函数、无副作用」三大特性,平衡代码简洁性与可维护性,拒绝为炫技过度抽象。
- 场景适配优先:仅在适合函数式编程的场景使用(数据处理、状态计算等),规避生命周期敏感、高频性能等不适配场景。
- 可读性至上:代码编写需兼顾新人理解成本,避免过度嵌套与晦涩语法,注释清晰、命名规范。
- 性能底线:在保证代码简洁的前提下,规避函数式编程的性能开销,必要时回退到命令式编程。
二、命名规范(强制执行)
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,需明确参数名,不建议用_省略(除非参数无需使用)。
- 代码长度:单个Lambda代码长度不超过5行,超过5行需拆分独立函数。
3.3 流式操作规范
- 集合处理:所有流式操作(map/filter/flatMap/groupBy等)必须使用asSequence()优化,避免创建中间集合,减少内存开销。
- 链式限制:流式操作的链式调用不超过5个操作符,超过5个需拆分,每个操作符单独换行并添加注释。
3.4 纯函数编写规范
- 无副作用:纯函数内部不修改外部变量、不执行IO操作(SP写入、数据库更新、网络请求)、不操作View。
- 输入决定输出:相同的输入必须返回相同的输出,不依赖外部状态。
- 禁止:在纯函数中使用全局变量、静态变量,或执行有副作用的操作。
四、场景使用规范(强制执行)
4.1 优先使用函数式编程的场景
- 数据转换与数据流处理:网络请求结果解析、JSON→Model映射、列表过滤/排序/分组、Flow/RxJava流式处理、Room查询结果格式化。
- 回调简化与通用逻辑封装:View点击事件、RecyclerView item点击事件简化,高阶函数封装权限申请、重试、延时等通用逻辑。
- UI状态计算与映射:Compose中UI状态推导、页面状态联动、网络请求状态转换(加载中/成功/失败)。
- 纯业务逻辑与工具类方法:数据校验、数据格式化、字符串/集合工具类方法。
- 并发安全场景:多线程数据传递、并发计算(利用不可变性避免线程竞争)。
4.2 禁止/谨慎使用函数式编程的场景
- 生命周期敏感的UI操作:Activity/Fragment生命周期相关操作、View创建、Dialog/Toast弹出。
- 高频性能场景:RecyclerView快速滑动(onBindViewHolder高频调用)、动画onDraw/onMeasure、触摸事件onTouch。
- 强副作用逻辑:连续修改外部变量、执行SP/文件写入、数据库更新等IO操作。
- 维护成本高的场景:团队新手过多的老项目,不建议全量使用函数式编程,仅在新代码中逐步适配。
- 内存敏感模块:图片加载、大文件处理、视频处理(需精准控制内存,避免函数式产生的临时对象)。
五、禁止行为(红线,不可触碰)
- 禁止在函数式代码中操作View(如setText、showDialog、setVisibility等)。
- 禁止在函数式代码中捕获生命周期对象(Activity、Fragment、Context),避免内存泄漏。
- 禁止在主线程高频调用函数式操作(如RecyclerView onBindViewHolder、动画绘制、触摸事件监听)。
- 禁止为了炫技而过度抽象(如用函数式封装简单的if-else逻辑,导致代码可读性下降)。
- 禁止在函数式代码中执行强副作用操作(SP写入、数据库更新、网络请求、修改外部变量)。
- 禁止Lambda嵌套超过2层、流式操作链式调用超过5个且无注释。
- 禁止用var修饰不可变变量,禁止纯函数依赖外部状态。
- 禁止使用全局高阶函数(优先使用局部高阶函数或类内成员函数,减少内存占用)。
六、内存与安全规范(强制执行)
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检查项(强制执行)
- 命名规范:高阶函数、纯函数、变量、常量命名是否符合本规范。
- 语法规范:Lambda嵌套是否≤2层,流式操作是否使用asSequence(),链式调用是否≤5个且有注释。
- 场景规范:是否在不适配场景使用函数式编程(如生命周期UI操作、高频性能场景)。
- 禁止行为:是否存在红线行为(如捕获生命周期对象、操作View、强副作用等)。
- 内存安全:闭包使用是否规范,不可变性是否符合要求,是否存在内存泄漏风险。
- 可读性:代码是否清晰,注释是否完整,复杂逻辑是否拆分独立函数。