2025.1 版本已经发布,在此之前我们就聊过该版本的 《Terminal 又发布全新重构版本》,而现在 2025.1 中的 K2 模式也成为了默认选项。
可以预见,这个版本可能会包含不少大坑,为下个 Android Studio 祈祷。
首先有一点可以确定,随着 K2 模式成为默认选项,虽然 K1模式仍可使用,但后续 K1 将不再支持新语言特性和 IDE 优化,所以在 2025.1 里,你依然可以在 Language & FRameworks > Kotlin
里关闭 K2 模式,但是只能说「逃得了一时是一时」:
“K2” 对应的是 Kotlin 插件包含用于代码分析的 K2 Kotlin 编译器的内部版本,而 K1 模式使用 K1 编译器,IntelliJ IDEA 中内置的 Kotlin 编译器版本完全独立于项目构建文件中指定的版本,但它可能会影响项目中支持的 Kotlin 版本范围。
在之前的《K2 模式已发布稳定版》我们提到过,IntelliJ IDEA 的 K2 模式并不依赖于项目构建设置中指定的 Kotlin 编译器版本,K2 模式代表 IDE 中对 Kotlin 编辑场景支持的几乎完全重写,而使用 K2 编译器可以带来:
- 高达 94% 的编译速度提升
- 在初始化阶段的速度提高了 488%
- 与之前的编译器相比,Kotlin K2 编译器在分析阶段的速度提高了 376%
- ····
所以基于 K2 编译器能力的 K2 模式,在 Kotlin 代码分析、补全和导航速度方面取得了巨大进步,这体现在全新 IDE 下就是:
- 提高代码分析的性能(如高亮、补全速度)
- 更快的查找和跳转
- 支持 Kotlin 2.0 及以上版本的新语言特性
而 IDE 一直以来都深度依赖 K1 ,所以其实在迁移到 K2 的过程中,会有大量的重写和功能重构,这也是 K2 到现在还一直需要打磨的原因。
而在 K1 到 K2 的变化里,其中最大的就是全新的 Kotlin Analysis API ,它提供了一种清晰稳定的方式来访问代码信息,并且不需要依赖编译器内部结构。
Kotlin Analysis API 在 K2 模式里采用模块化架构,支持 IDE 功能(如补全、检查)独立调用编译器的特定分析阶段(如解析或类型检查),避免不必要的全量分析,从而提升性能。
K2 编译器放弃了 K1 中隐式的 laziness,转而采用显式的分阶段代码分析架构, K2 编译器会分阶段分析代码(如 SUPER_TYPES 计算类的 supertypes ,TYPES 处理函数 signature types),每个阶段逐步为抽象语法树(AST)添加语义信息。
另外,在 K1 模式里 Kotlin Analysis API 的分析操作通常受限于单一的全局解析锁(global resolution lock),例如 Find Usages 等功能会持有全局锁,导致其他功能(如代码高亮、补全)无法并行执行,造成性能瓶颈。
而 K2 编译器的解析逻辑是并发容忍(concurrency-tolerant),Kotlin Analysis API 利用这一特性,消除了全局锁,API 现在支持同时分析多个声明(declarations),即使在复杂场景(如两个函数相互调用)中也能高效处理:
虽然 K2 编译器目前还是使用单线程分析(因为多模块并行编译已利用多核),但是目前的并发容忍设计为未来的多线程分析奠定了基础,后续 Kotlin Analysis API 可无缝适配。
而在插件迁移适配上,Kotlin Analysis API 也起到了很大作用,它封装了所有复杂的解析逻辑,并提供具有清晰且可预测行为的记录抽象,开发者只需请求他需要的语义代码信息片段,API 会处理所有延迟和并行分析并缓存结果。
例如要获取表达式类型,开发者只需调用库提供的 KtExpression.expressionType
扩展属性 ,如果类型尚不清楚,则将自动分析包含声明的 body :
fun KtExpression.hasStringType(): Boolean {analyze(this) {return expressionType == builtinTypes.string}
}
而事实上,不管你的项目是不是 K2 ,都可以享受到新 IDE 在 K2 模式下带来的性能提升,而如果你开发或使用的是插件,那么可能会需要将部分依赖旧的 Kotlin 插件进行迁移,例如:
- 旧的编译器 API
SPECIAL_ANNOTATION_NAME = FqName("my.app.Special")fun hasAnnotation(declaration: KtDeclaration): Boolean {val bindingContext = declaration.analyze()val descriptor = bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, declaration]?: return falsereturn descriptor.annotations.hasAnnotation(SPECIAL_ANNOTATION_NAME)
}
- 新 Analysis API
val SPECIAL_ANNOTATION_CLASS_ID = ClassId.fromString("my/app/Special")fun hasAnnotation(declaration: KtDeclaration): Boolean {analyze(declaration) {return SPECIAL_ANNOTATION_CLASS_ID in declaration.symbol.annotations}
}
另外,就像前面说的,关于一些新特性,比如 Kotlin 2.1 的新支持就会仅限于 K2 模式的 IDE,例如:
- Non-local 的 break/continue :
fun processList(elements: List<Int>): Boolean {for (element in elements) {val variable = element.nullableMethod() ?: run {log.warning("Element is null or invalid, continuing...")continue // 在早期不能在 forEach 的 lambda 中直接使用 continue}if (variable == 0) return true // If variable is zero, return true}return false
}
- 在 when 里使用 guard condition:
sealed interface Animal {data class Cat(val mouseHunter: Boolean) : Animal {fun feedCat() {}}data class Dog(val breed: String) : Animal {fun feedDog() {}}
}fun feedAnimal(animal: Animal) {when (animal) {// Branch with only the primary condition. Returns `feedDog()` when `Animal` is `Dog`is Animal.Dog -> animal.feedDog()// Branch with both primary and guard conditions. Returns `feedCat()` when `Animal` is `Cat` and is not `mouseHunter`is Animal.Cat if !animal.mouseHunter -> animal.feedCat()// Returns "Unknown animal" if none of the above conditions matchelse -> println("Unknown animal")}
}
- 多美元字符串插值,通过初始
$$
表示需要两个美元符号 ($$
) 来触发插值,防止$schema
、$id
和$dynamicAnchor
被解释为插值标记:
val KClass<*>.jsonSchema : Stringget() = $$"""{"$schema": "https://json-schema.org/draft/2020-12/schema","$id": "https://example.com/product.schema.json","$dynamicAnchor": "meta""title": "$${simpleName ?: qualifiedName ?: "unknown"}","type": "object"}"""
最后,未来即将更新的 Android Studio 也会一样默认开始 K2 模式,所以作为 Android 开发,对于下一个版本的 AS 更新还需要慎重,因为你也不知道会有什么坑在等着你。
当然,最后还是要强调:
- K2 编译器是 Kotlin 语言的新一代编译器
- K2 Mode 是 IntelliJ IDEA 的一种运行模式
K2 Mode 是 IDEA 利用 K2 编译器的前端(解析和语义分析部分)来增强 IDE 的 Kotlin 代码理解能力,但不直接参与项目的实际编译,功能范围仅限于 IDE 的交互体验。
所以理论上,你项目用 K1,也不影响你体验 K2 Mode ,但是如果你项目使用 K2,那么强烈建议开始 K2 Mode 来体验全新的特性。
那么,你已经体验过 K2 模式了么?
参考资料
-
https://blog.jetbrains.com/idea/2025/04/k2-mode-in-intellij-idea-2025-1-current-state-and-faq/
-
https://blog.jetbrains.com/idea/2025/04/the-story-behind-k2-mode-and-how-it-works/