第71章:代码风格——Kotlin编码规范、ktlint、detekt、Spotless
代码风格这事儿,说大不大,说小不小。
我见过不少团队,功能写得飞起,但一打开代码库,缩进乱七八糟、命名随心所欲、空行全看心情。说实话,这种代码看着就累。更别提接手维护的时候,那种想砸键盘的冲动——嗯,我经历过。
Kotlin 这门语言本身就很讲究「优雅」。如果你写出来的代码跟 Java 似的,那还不如用 Java。今天我们就聊聊怎么让 Kotlin 代码既规范又漂亮,顺便用工具把这些事自动化掉。
为什么要在意代码风格?
你可能觉得:「能跑不就行了?」
我以前也这么想。直到有一次,我接手一个遗留项目,里面同一个文件里混着四种不同的命名风格——驼峰、下划线、匈牙利命名法,甚至还有拼音缩写。我花了整整两天才搞清楚一个核心类的逻辑。从那以后,我对代码风格的态度就变了。
说白了,代码风格不是给机器看的,是给人看的。机器只关心语法对不对,人还得关心逻辑清不清晰、结构合不合理。统一的风格能让你少掉很多头发。
Kotlin 官方编码规范
Kotlin 官方其实有一套非常详细的编码规范。我挑几个重点说说,都是我在项目中踩过坑的地方。
命名规则
- 类名:大驼峰(PascalCase)。比如
UserRepository、HttpClient - 函数名/变量名:小驼峰(camelCase)。比如
getUserById()、userName - 常量:大写加下划线。比如
MAX_RETRY_COUNT、DEFAULT_TIMEOUT - 包名:全小写,不要用下划线。比如
com.example.myapp
这里有个坑:Kotlin 的 const val 只能用在顶层或者 object 里。我见过有人把常量写在 companion object 里,结果发现编译报错——嗯,注意一下。
冒号与空格
Kotlin 的冒号前后空格有讲究:
// 正确
class User : BaseEntity
val map: Map<String, Int> = emptyMap()
// 错误
class User:BaseEntity
val map:Map<String,Int>=emptyMap()
我个人习惯在冒号前加一个空格,后面也加一个。这样看着舒服,也符合官方规范。
Lambda 表达式
Kotlin 的 lambda 很常用,但写法上容易乱。官方建议:
// 推荐
list.filter { it.isActive }
.map { it.name }
// 不推荐
list.filter({ it.isActive }).map({ it.name })
如果 lambda 是函数的最后一个参数,直接写在括号外面。这是 Kotlin 的特色,别浪费了。
ktlint:格式化你的代码
ktlint 是我用得最多的工具。它不光是检查,还能自动修复。说白了,你写完代码跑一下 ktlint --format,它就把缩进、空格、换行这些琐事全帮你搞定了。
安装方式很简单:
// Gradle 配置
plugins {
id("org.jlleitschuh.gradle.ktlint") version "11.0.0"
}
// 运行
./gradlew ktlintFormat
ktlint 的规则是硬编码的,不能自定义。这其实是个好事——省得团队里为「到底用几个空格缩进」吵半天。
detekt:静态分析利器
ktlint 管的是格式,detekt 管的是「代码质量」。它会检查你的代码有没有潜在问题,比如:
- 函数太长(默认超过 20 行就报警)
- 嵌套太深(超过 4 层就提示)
- 未使用的变量或参数
- 复杂的表达式
我记得有一次,detekt 帮我发现了一个隐藏的 bug——一个变量被赋值了两次,但第二次赋值其实是拼写错误。这种问题肉眼很难看出来,但工具一抓一个准。
// detekt 配置示例(detekt.yml)
complexity:
LongParameterList:
threshold: 6
LargeClass:
threshold: 300
style:
MaxLineLength:
maxLineLength: 120
detekt 的规则可以自定义。你可以根据团队情况调整阈值。比如我习惯把函数长度阈值设到 30 行,因为有些业务逻辑确实没法拆得太碎。
Spotless:统一全项目格式
Spotless 是个通用格式化工具,不光支持 Kotlin,还支持 Java、Groovy、Markdown 等。如果你项目里混着多种语言,用 Spotless 可以统一管理。
// Gradle 配置
spotless {
kotlin {
ktlint()
target("**/*.kt")
}
kotlinGradle {
ktlint()
target("*.gradle.kts")
}
}
// 运行
./gradlew spotlessApply
Spotless 的好处是「一键格式化」。你跑一次,整个项目的代码风格就统一了。我一般在 CI 里加一步 spotlessCheck,如果格式不对,构建直接失败。
工具对比与选择
这三个工具各有侧重,我整理了个表格:
| 工具 | 主要功能 | 能否自定义 | 推荐场景 |
|---|---|---|---|
| ktlint | 代码格式化 | 否(硬编码规则) | 快速统一格式 |
| detekt | 静态分析 | 是(可配置阈值) | 发现潜在问题 |
| Spotless | 多语言格式化 | 是(可配置引擎) | 全项目统一管理 |
我个人建议:ktlint + detekt 组合使用。ktlint 管格式,detekt 管质量。如果项目里还有其他语言,再加个 Spotless。
避坑指南
我曾经在一个项目里同时用了 ktlint 和 detekt,结果发现它们对某些规则有冲突。比如 ktlint 要求 import 语句按字母排序,但 detekt 默认不检查这个。后来我统一用 ktlint 的规则,detekt 只开质量相关的检查。
还有一次,我把 detekt 的 MaxLineLength 设成了 80,结果发现 Kotlin 的链式调用经常超长。后来改到 120,世界清净了。
知识体系图
下面这张图展示了本章的核心逻辑:
写在最后
代码风格这件事,说白了就是「约定」。没有绝对的对错,只有是否统一。我见过用 2 空格缩进的团队,也见过用 4 空格的,只要全项目一致,都没问题。
工具只是辅助,关键还是人。你想想看,如果每个人都自觉遵守规范,那工具其实可有可无。但现实是——人总会偷懒,总会疏忽。所以,让工具来兜底吧。
嗯,今天就聊到这儿。希望你的 Kotlin 代码,既优雅又健壮。
公众号:蓝海资料掘金营,微信 deep3321