专注于 JetBrains IDEA 全家桶,永久激活,教程
持续更新 PyCharm,IDEA,WebStorm,PhpStorm,DataGrip,RubyMine,CLion,AppCode 永久激活教程

IntelliJ IDEA 2025.1发布:K2模式成默认,提升Kotlin编译性能,探索新特性

2025.1 版本已经发布,在此之前我们就聊过该版本的[Terminal 又发布全新重构版本][],而现在 2025.1 中的 K2 模式也成为了默认选项。

IntelliJ IDEA 2025.1版本已发布,K2模式成为默认选项,带来Kotlin编译速度的巨大提升,支持Kotlin 2.0及以上新特性。本文深入探讨K2模式的优势、Kotlin编译器的优化、分析API的革新,以及如何体验这些变化,助力Kotlin开发者提升效率和体验。


可以预见,这个版本可能会包含不少大坑,为下个 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),即使在复杂场景(如两个函数相互调用)中也能高效处理:

 image-20250417140125624

虽然 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 false

    return 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 match
        else -> println("Unknown animal")
    }
}
  • 多美元字符串插值,通过初始 $$ 表示需要两个美元符号 ( $$ ) 来触发插值,防止 $schema 、 $id 和 $dynamicAnchor 被解释为插值标记:
val KClass<*>.jsonSchema : String
    get() = $$"""
    {
      "$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 更新还需要慎重,因为你也不知道会有什么坑在等着你。

&nbsp;

当然,最后还是要强调:

  • K2 编译器是 Kotlin 语言的新一代编译器
  • K2 Mode 是 IntelliJ IDEA 的一种运行模式

K2Mode 是 IDEA 利用 K2 编译器的前端(解析和语义分析部分)来增强 IDE 的 Kotlin 代码理解能力,但不直接参与项目的实际编译,功能范围仅限于 IDE 的交互体验。

所以理论上,你项目用 K1,也不影响你体验 K2 Mode ,但是如果你项目使用 K2,那么强烈建议开始 K2 Mode 来体验全新的特性。

那么,你已经体验过 K2 模式了么?

参考资料

未经允许不得转载:搜云库 » IntelliJ IDEA 2025.1发布:K2模式成默认,提升Kotlin编译性能,探索新特性

JetBrains 全家桶,激活、破解、教程

提供 JetBrains 全家桶激活码、注册码、破解补丁下载及详细激活教程,支持 IntelliJ IDEA、PyCharm、WebStorm 等工具的永久激活。无论是破解教程,还是最新激活码,均可免费获得,帮助开发者解决常见激活问题,确保轻松破解并快速使用 JetBrains 软件。获取免费的破解补丁和激活码,快速解决激活难题,全面覆盖 2024/2025 版本!

联系我们联系我们