本文由 简悦SimpRead 转码, 原文地址 mbonnin.medium.com
不确定你是否应该使用kotlin-stdlib-jdk8...
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 commit和release 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 (*)
我们还可以在mavenCentral(repo.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从我的项目中删除之前,请让我知道!