[Android翻译]不同的kotlin-stdlibs的解释

2,047 阅读4分钟

本文由 简悦SimpRead 转码, 原文地址 mbonnin.medium.com

不确定你是否应该使用kotlin-stdlib-jdk8...

image.png

I heart coffee by jojo 77

(不确定你是否应该使用kotlin-stdlib-jdk8...)

编辑2022-06-30:重写了结论,强调Kotlin Gradle插件现在会自动添加stdlib

我喜欢Kotlin,因为它是一种简洁而强大的语言,具有非常合理的默认值和设计决定。在这方面,它采用了Python的禅。

应该有一种--最好是只有一种--明显的方法来做。

但有一个领域是失败的,那就是stdlib的配置。这有点讽刺,因为它也是你作为一个Kotlin新手首先要配置的东西之一。

下面这些东西中什么是最好的?在部分支持Java 8的Android设备上,你应该选择什么?

// so many stdlib to choose from!
implementation("org.jetbrains.kotlin:kotlin-stdlib-jre8")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jre7")
implementation("org.jetbrains.kotlin:kotlin-stdlib")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7")

这些都是简单的。两年前,它们已经被弃用,取而代之的是-jdk7和-jdk8,所以你可以忘记它们。这样做是为了适应java9的模块系统,更具体地说是为了避免split packages。你可以从github commitrelease notes中阅读细节。

你可能偶尔会看到它们。不要使用它们。

根据Kotlin doc的说法。

Kotlin标准库kotlin-stdlib针对Java 6及以上版本。有一些标准库的扩展版本,增加了对JDK 7和JDK 8的一些特性的支持。要使用这些版本,请添加以下一个依赖项,而不是kotlin-stdlib。

事实上,如果你看一下kotlin-stdlib-jdk7 pom文件,你可以看到它过渡地依赖kotlin-stdlib。

<dependency>
   <groupId>org.jetbrains.kotlin</groupId>
   <artifactId>kotlin-stdlib</artifactId>
   <version>1.3.50</version>
   <scope>compile</scope>
</dependency>

如果你包含kotlin-stdlib-jdk7,它将拉动kotlin-stdlib。

如果你包括kotlin-stdlib-jdk8,它将拉动kotlin-stdlib-jdk7和kotlin-stdlib。你也可以通过运行./gradlew :dependencies来检查。

compileClasspath - Compile classpath for compilation 'main' (target  (jvm)).
\--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.50
     +--- org.jetbrains.kotlin:kotlin-stdlib:1.3.50
     |    +--- org.jetbrains.kotlin:kotlin-stdlib-common:1.3.50
     |    \--- org.jetbrains:annotations:13.0
     \--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.50
          \--- org.jetbrains.kotlin:kotlin-stdlib:1.3.50 (*)

我们还可以在mavenCentralrepo.maven.apache.org/maven2/org/… )上检查大小。

martin@bowser-castle$ ls -al kotlin-stdlib-*.jar
1326269 Sep 14 16:58 kotlin-stdlib-1.3.50.jar
   3129 Sep 14 16:58 kotlin-stdlib-jdk7-1.3.50.jar
  15476 Sep 14 16:58 kotlin-stdlib-jdk8-1.3.50.jar

kotlin-stdlib是1MB以上,而其他两个最多只有几KB。这证实了大部分功能都在kotlin-stdlib中,并在-jdk7和-jdk8中有所补充。

因此,让我们拉出kotlin-stdlib-jdk8,我们就可以得到所有的东西了,对吗?嗯......不那么确定,让我们看看这些工件里面有什么。

kotlin-stdlib

包含。

  • 大部分的功能。集合、范围、数学、Regex、文件扩展、锁,等等。你日常使用的大部分功能都在kotlin-stdlib中。

kotlin-stdlib-jdk7

包含。

  • 无反射的抑制性异常

抑制异常是在Java 7中与try-with-resources同时添加的。它在释放资源时抛出的异常给出了更多信息。

val closeable = object: Closeable {
    override fun close() {
        throw Exception("exception from close")
    }
}

closeable.use {
    throw Exception("exception from use")
}
// Java6:
// Exception in thread "main" java.lang.Exception: exception from use
//    at com.example.MainKt.main(Main.kt:13)


// Java7 +:
//
// Exception in thread "main" java.lang.Exception: exception from use
// at MainKt.main(Main.kt:11)
// at MainKt.main(Main.kt)
// Suppressed: java.lang.Exception: exception from close
//    at MainKt$main$closeable$1.close(Main.kt:6)
//    at kotlin.io.CloseableKt.closeFinally(Closeable.kt:56)
//    at MainKt.main(Main.kt:10)
//    ... 1 more

kotlin-stdlib在Java 7+上支持这个带反射

kotlin-stdlib-jd7也是这样做的没有反射

除了Closeable类型,Java 7还引入了AutoCloseable。kotlin-stdlib-jdk7在这个类型上也增加了use扩展函数。

kotlin-stdlib-jdk8

包含。

  • Java 8的流扩展

kotlin-stdlib-jdk8增加了从java.util.Stream转换到kotlin.sequences.Sequence和kotlin.collection.List的扩展函数(source)

  • 持续时间扩展

kotlin-stdlib-jdk8添加了扩展函数,以转换为/从java.time.Duration和kotlin.time.Duration(来源)。

  • 正则表达式中的命名组

kotlin-stdlib-jdk8 增加了对 named groups的支持。(?<name>group)将捕获反向参考 "name "下的组的匹配。

请注意,虽然命名组始于Java 7,但其实现直到Java 8才完成

kotlin-stdlib-jdk8将默认ThreadLocalRandom为Random.Default。这应该可以消除多线程情况下的一些争论(stackoverflow),尽管在Java 6&7上有一个退步,即使用ThreadLocal来模拟ThreadLocalRandom。同样,ThreadLocalRandom也是在Java 7上开始的,但是错误的,所以只在Java 8上添加了它。

在Android上用什么?

每次,-jdk7和-jdk8神器都会增加PlatformImplementations和扩展函数的组合。但在设备上真正使用的是什么?

我的像素3报告System.getProperty("java.specification.version")="0.9"。0.9是低于Java 7的。我甚至不确定它是否符合Java 6。另外,System.getProperty("java.vm.name")返回"Dalvik"。因此,看起来这是在报告一些自定义的Android虚拟机。

这在运行时不会被stdlib接收到。这意味着无论你在classpath中放入什么工件,stdlib都会回到默认的PlatformImplementations

由于Android支持API级别为26+的java.time.Duration和API级别为24+的Stream API(doc),这意味着。

// https://github.com/JetBrains/kotlin/blob/65244b4bea81f737466618927d4f3afe339cad0d/libraries/stdlib/jvm/src/kotlin/internal/PlatformImplementations.kt#L42
internal val IMPLEMENTATIONS: PlatformImplementations = run {
    val version = getJavaVersion()
    if (version >= 0x10008) {
        try {
            return@run castToBaseType<PlatformImplementations>(Class.forName("kotlin.internal.jdk8.JDK8PlatformImplementations").newInstance())
        } catch (e: ClassNotFoundException) { }
        try {
            return@run castToBaseType<PlatformImplementations>(Class.forName("kotlin.internal.JRE8PlatformImplementations").newInstance())
        } catch (e: ClassNotFoundException) { }
    }

    if (version >= 0x10007) {
        try {
            return@run castToBaseType<PlatformImplementations>(Class.forName("kotlin.internal.jdk7.JDK7PlatformImplementations").newInstance())
        } catch (e: ClassNotFoundException) { }
        try {
            return@run castToBaseType<PlatformImplementations>(Class.forName("kotlin.internal.JRE7PlatformImplementations").newInstance())
        } catch (e: ClassNotFoundException) { }
    }

    PlatformImplementations()
}
  • jdk8 ThreadLocalRandom在任何API级别上都不会被使用。
  • jdk8 命名组将在所有API级别上的运行时抛出。
  • jdk8持续时间扩展将在API级别26以上工作。
  • jdk8流扩展将在API级别24以上工作。
  • jdk7的无反射抑制异常在任何API级别上都不会被使用。

持续时间扩展仅仅是两行实验性代码。流扩展要多一点,但如果你使用Kotlin,你可以(当然也应该)用序列或集合代替它们。

另一方面,依赖kotlin-stdlib-jdk8会增加JDK7/JDK8PlatformImplementations代码。虽然它不是很大,但R8将无法剥离它,因为它在运行时使用,取决于Java规范的版本,在Android上似乎总是0.9。

综合考虑,普通的kotlin-stdlib似乎是Android上的最佳候选者。由于-jdk7和-jdk8中的大部分功能都无法访问,它避免了下载额外的工件和加载额外的字节码。不过这似乎有点违反直觉,因为我本来以为会是相反的。

注意,如果你使用Kotlin 1.4+,Kotlin Gradle插件现在默认添加了stdlib-jdk8。如果你想退出,你可以在gradle.properties中用kotlin.stdlib.default.dependency=false选择退出。

你用的是什么?在我把所有的jdk8从我的项目中删除之前,请让我知道!


www.deepl.com 翻译