java系统找不到指定文件怎么解决
293
2022-09-14
Kotlin 1.5新特性记录
文章目录
1 1.5.0 新特性
1.1 语言特性
支持 JVM 记录类Sealed 接口内联类
1.2 Kotlin / JVM
稳定的基于IR的 JVM 编译器新的默认 Jvm 构建版本 是1.8通过 invokedynamic 来调用 SAM使用 invokedynamic 调用 lmabda 表达式@JvmDefault 和旧的 Xjvm-default 已弃用改进了可空性注解
1.3 标准库 stdlib
稳定的无符号整数类型稳定的区域无关API,用于转换大小写文本稳定的字符转整数API稳定的 Path Api`Duration` Api 更改新的集合函数 firstNotNullOfString?.toBoolean() 函数更加严格
2 1.5.20 新特性
2.1 Kotlin /JVM
通过 invokedynamic 连接字符串支持 JSpecify 空注释
3 1.5.30 新特性
3.1 语言特性
使 sealed 和 Boolean 的 when 流程控制更加详尽挂起函数作为超类型要求选择性加入实验性 API 的隐式用法改进了推断递归泛型类型消除构建器推断限制
1 1.5.0 新特性
Kotlin 1.5.0 的新增项:
新的语言特性稳定的基于IR的 JVM 编译器后台性能提高提供对特性的渐进式更改,例如稳定实验性特性,和淘汰过时的特性
1.1 语言特性
支持 JVM 记录类
Java 正在快速的发展,为了保证 Kotlin 和它的互操作性,我们引入了 JVM 最新的一个新特性 - record classes(记录类)。
Kotlin 对 JVM 记录类的支持包括双向互操作性:
在 Kotlin 代码中,可以直接 Java 的记录类,就像其它类那样如果需要在 Java 中使用 Kotlin 记录类,请使这个类作为一个数据类型,并使用@JvmRecord 注解修饰它
@JvmRecorddata class User(val name: String, val age: Int)
更多请看: Learn more about using JVM records in Kotlin
Sealed 接口
Kotlin 的接口现在可以使用 selaled 修饰符,它对接口的工作方式与对类的工作方式相同:密封接口的所有实现在编译时都是已知的。
sealed interface
例如,你可以根据这一特性来写 when:
fun draw(polygon: Polygon) = when (polygon) { is Rectangle -> // ... is Triangle -> // … // 不必在写 else 分支 ,因为所有的可能的实现都已覆盖}
此外,在之前,密封只能由继承实现,而现在,密封接口可以更加灵活的支持那些受到限制的层次结构,因为一个类可以直接实现多个密封接口:
class FilledRectangle: Polygon,
更多请看:Learn more about sealed interfaces
内联类
内联类是基于值的子集合,这些类只用于保存值。你可以将它们看做一个值的包装类,并且你不用担心因为包装新类而带来的额外内存开销。这个特性在1.4就已经有了实验性 api,这一点可以看:使用内联类。
value class Password(val s: String)
在 JVM 上,字段还需要一个特殊的 @JvmInlin 来修饰:
@JvmInlinevalue class Password(val s: String)
inline 修饰符现在已经弃用。
Learn more about inline classes.
1.2 Kotlin / JVM
Kotlin / JVM 得到了许多改进,包括内部的和面向用户的。下面是几个最值得注意的几个。
稳定的基于IR的 JVM 编译器
基于 IR 的 Kotlin / JVM 的编译器现在已经是稳定的了,并且在默认情况下会启用它。
从 Kotlin 1.4.0 开始,基于 ir 的编译器早期版本便已经开始是 preview 状态(可以手动使用),现在它已经成为了 1.5 的默认特性。 在较早的 Koltin 版本中,默认仍然使用早期的编译器版本。
你可以在这篇Blog中找到更多关于基于 IR 支持的好处,以及未来发展的方向:Blog 原文。
如果你需要在 Kotlin1.5.0 版本使用旧的编译支持,你可以在配置文件中添加下面的代码:
gradle 中
tasks.withType
maven 中
新的默认 Jvm 构建版本 是1.8
现在 Kotlin / Jvm 编译的默认构建版本是 1.8,1.6版本被标注为已废弃。
如果你需要用 JVM 1.6 版本来构建,你仍然可以切到这个版本去。
通过 invokedynamic 来调用 SAM
Kotlin 1.5.0 现在使用动态调用 (invokedynamic) 来编译 SAM(单一抽象方法)转换,它可以涵盖:
任意 Java 接口的 SAM 类型任意是 Kotlin 函数式接口的 lamdba 表达式
新的实现使用 LambdaMetafactory.metafactory() 方法,并且在编译期间不再生成辅助包装类。这减小了应用程序 Jar 包的大小,从而提高了 JVM 的启动性能。
如果要回滚到以前那种编译成匿名类的旧实现,可以添加下面选项:
-Xsam-conversions=class
可以通过 Gradle、Maven、command-line compiler 几篇文章进行学习。
使用 invokedynamic 调用 lmabda 表达式
将普通的 Koltin Lambda 编译为 invokedynamic 是实验性的,这种特性可以在任意时候被删除或更改。你应该只将其用于预研一些需求
Kotlin 1.5.0 引入了对将普通的 Kotlin lambda(未转换为函数接口的实例)编译为动态调用(invokedynamic)的实验性支持。该实现使用 LambdaMetafactory.metafactory() 生成更轻的二进制文件,它在运行时有效地生成必要的类。目前,与普通的 lambda 编译相比,它有三个限制:
编译成 invokedynamic 的 lambda 是不可序列化的对这样的 lambda 调用toString 函数可能会产生可读性较差的内容实验性的反射 API 不支持那些LambdaMetafactory 创建的 lamdba 表达式
@JvmDefault 和旧的 Xjvm-default 已弃用
在 Kotlin 1.4.0 之前,有 @JvmDefault 注解, 以及可以设置 -Xjvm-default=enable、-Xjvm-default=compatibility。它们用于为 Kotlin 接口中所有特定的非抽象成员创建 JVM 默认方法。
在 Kotlin1.4.0中,我们引入了新的方式: 官方文档,它为整个项目默认打开了这种特性。
在 Kotlin 1.5.0 中,我们已经弃用了 @JvmDefault注解和 -Xjvm-default=enable、-Xjvm-default=compatibility。
Learn more about default methods in the Java interop
改进了可空性注解
Kotlin 支持使用可空性注解,来处理来自 Java 的可空属性。Kotlin 1.5.0 对这种特性做了下面的改进:
它可以在编译后的 Java 库中读取类型参数上的可空性注释,这些注解将用作依赖项(传递可空性注解)它支持以TYPE_USE 注解为目标,进行可空注解:
ArraysVarargsFields类型参数(泛型)及其边界基类和接口的类型参数
如果可空性注释有多个适用于某个类型的目标,并且其中一个目标是TYPE_USE,那么首选TYPE_USE。例如,如果@Nullable 同时支持TYPE_USE 和METHOD 作为目标,方法签名@Nullable String[] f() 会变成fun f(): Array
对于这些新支持的情况,在从Kotlin调用Java时,使用错误的可空性类型会产生警告。使用 -xtype-enhance-improvement -strict-mode 编译器选项来去掉这些警告。
Learn more about null-safety and platform types.
1.3 标准库 stdlib
稳定的无符号整数类型
UInt、ULong、UByte、UShort 这些无符号的数字现在都是稳定的了。对这些类型、范围及其递增的操作也是如此,无符号数组及其操作仍保留在 Beta 中。
Learn more about unsigned integer types
稳定的区域无关API,用于转换大小写文本
这个版本带来一个新的与区域无关的 API,用于大/小写文本转换。它提供了以前 toLowerCase、 toUpperCase、capitalize() 和 decapitalize() 这些函数的替代方法,这些 API 函数对语言环境更敏感,可以帮助你避免由于不同的地区设置而产生的错误。
从 Kotlin 1.5 后,可以使用下面的替代函数:
旧的 API 函数被标记为弃用,并在将来的版本中删除。
可以参考 Git文档来查看更加完整的函数列表。
稳定的字符转整数API
从 Kotlin 1.5.0 开始,char-to-code 和 char-to-digit 转化的函数已经是稳定的了。这些函数取代了当前的 API 函数,而当前的 API 函数常常与 string-to-Int 转换相混淆。
新的 API 消除了这种命名歧义,使代码的行为更加透明和明确。
这个版本引入了 Char 类型的转换,这些转换被划分为以下几个明确命名的函数集:
根据给定的整型构造出对应的Char
fun Char(code: Int): Charfun Char(code: UShort): Charval Char.code:
将 Char 转换为它所代表的数字值:
fun Char.digitToInt(radix: Int): Intfun Char.digitToIntOrNull(radix: Int): Int?
Int 的扩展函数,用于将其表示的非负整数转换为相应的Char
fun Int.digitToChar(radix: Int):
旧的转换 api,包括 Number.toChar ,及其实现(除了 Int.toChar)和 Char 用于转化成数字的扩展函数,如 Char.toInt , 现在均已废弃。Learn more about the char-to-integer conversion API in KEEP.
稳定的 Path Api
带有 java.nio.file.Path 扩展的实验性 API 现在已经是稳定的了。
// 可以通过 “/” 来构造路径val baseDir = Path("/base")val subDir = baseDir / "subdirectory"// 列出目录中的文件val kotlinFiles: List
Learn more about the Path API.
Duration Api 更改
Duration 是一个实验性的Api,用于表示持续的时间,并有不同的单位支持。在1.5.0, Duration api做出了如下改变:
内部使用的值从Double 替换成Long,以提供更好的精度新增了 API 用于从Long 转化到特定的时间单位,它将取代旧的 Api,旧的 Api 使用Double 类型进行操作,现在已经弃用。 例如:Duration.inWholeMinutes 返回Long 类型的值, 替换了原来的Duration.inMinutes 函数新增了一些伴生函数用于通过数字来构造Duration,例如,Duration.secondes(Int) 创建一个Duration 独享,表示一个秒数整型。 旧的扩展属性,如Int.seconds 现在已弃用
val duration = Duration.milliseconds(120000)println("There are ${duration.inWholeSeconds} seconds in ${duration.inWholeMinutes} minutes")
新的集合函数 firstNotNullOf
新增了集合处理函数 firstNotNullOf() 和 firstNotNullOfOrNull() 函数,它们结合了 mapNotNull 和 fist() 或 firstOrNull()
通过传入自定义映射函数,并返回第一个非空值。 如果没有,可以根据情况抛异常或者返回null。
val data = listOf("Kotlin", "1.5")println(data.firstNotNullOf(String::toDoubleOrNull))println(data.firstNotNullOfOrNull(String::toIntOrNull))// 1.5// null
String?.toBoolean() 函数更加严格
对于已经有的 String?.toBoolean() 函数,引入了区分大小写的两个严格版本:
String.toBooleanStrict(), 除了 “true” / “false”,其他的字符串输入将会抛出异常String.toBooleanStrictOrNull,除了 “true” / “false”,其他的字符串输入将会返回 null
println("true".toBooleanStrict()) // trueprintln("1".toBooleanStrictOrNull()) // null// println("1".toBooleanStrict()) // Exception
2 1.5.20 新特性
2.1 Kotlin /JVM
通过 invokedynamic 连接字符串
Kotlin 1.5.20 在设置 JVM 编译版本 9+ 后,将字符串连接编译为动态调用(invokedynamic),从而与现代 Java 版本保持一致。更准确的说,它使用 StringConcatFactory.makeConcatWithConstants() 进行字符串连接。
如果要使用以前的 StringBuilder.append() 连接,请添加编译器选项 -XString-concat=inline。
支持 JSpecify 空注释
Kotlin 编译器可以读取各种类型的可空注解,从而将可空信息从 Java 传递给 Kotlin。 版本 1.5.20 引入了对 JSpecify 项目的支持,该项目包括一组标准的 Java 空注解。
下面是 Kotlin 如何处理 JSpecify 注释的示例:
// JavaClass.javaimport org.jspecify.nullness.*;@NullMarkedpublic class JavaClass { public String notNullableString() { return ""; } public @Nullable String nullableString() { return ""; }}
// Test.ktfun kotlinFun() = with(JavaClass()) { notNullableString().length // OK nullableString().length // Warning: receiver nullability mismatch}
在 1.5.20 中,根据 JSpecify 提供的空性信息,所有可空性不匹配都会被警告,在使用 JSpecify 时没使用 -Xjspecify-annotations=strict 和 -Xtype-enhancement-improvements-strict-mode 编译器选项来启用严格模式(带有错误报告)。请注意, JSpecify 项目正在积极开发中,它的 API 和实现可以在任何时候发生重大变化。
3 1.5.30 新特性
3.1 语言特性
使 sealed 和 Boolean 的 when 流程控制更加详尽
一个详尽的 when 状态语句应当涵盖所有可能的分支情况,并再加上一条 else 分支,也就是说 when 要包含所有可能的情况。
我们将计划禁止非穷举 when 状态语句的情况,使得其行为与 when 表达式一致。 为了能够顾确保迁移,可以配置编译器,使其在使用密封类或布尔值的语句时报告关于非穷举的错误。在 Kotlin1.6 中,默认情况下会出现这样的警告,以后将会变成错误。
sealed class Mode { object ON : Mode() object OFF : Mode()}fun main() { val x: Mode = Mode.ON when (x) { Mode.ON -> println("ON") }// WARNING: Non exhaustive 'when' statements on sealed classes/interfaces// will be prohibited in 1.7, add an 'OFF' or 'else' branch instead val y: Boolean = true when (y) { true -> println("true") }// WARNING: Non exhaustive 'when' statements on Booleans will be prohibited// in 1.7, add a 'false' or 'else' branch instead}
要在 Kotlin1.5.30中启用此特性,请使用 Kotlin 1.6 版本,你还可以通过启用 progressive mode模式将将警告改成错误。
kotlin { sourceSets.all { languageSettings.apply { languageVersion = "1.6" //progressiveMode = true // false by default } }}
挂起函数作为超类型
Kotlin 1.5.30 上可以让挂起函数作为超类型,但有一些限制:
class MyClass: suspend () -> Unit { override suspend fun invoke() { TODO() }}
使用 -language-version 1.6 编译器选项来启用该特性:
kotlin { sourceSets.all { languageSettings.apply { languageVersion = "1.6" } }}
该特性具有以下限制条件:
不能将普通函数和挂起函数类型混合作为超类型。这是由于 JVM 底层实现中挂起函数的实现细节造成的。它们在其中表示为带有标记接口的普通函数类型。由于使用了标记 (marker)接口,所以无法区分哪些超接口挂起了,哪些是普通。不能使用多个挂起函数超类型,如果有类型检查,你也不能使用多个普通函数超类型。
要求选择性加入实验性 API 的隐式用法
库的作者可以将一个实验性Api比较为 opt-in 来告知用户当前 api 的稳定状态。当使用 API 时,编译器会引发警告或错误。并且需要显式同意才能禁止使用。
// Library code@RequiresOptIn(message = "This API is experimental.")@Retention(AnnotationRetention.BINARY)@Target(AnnotationTarget.CLASS)annotation class MyDateTime // Opt-in requirement annotation@MyDateTimeclass DateProvider // A class requiring opt-in// Client code// Warning: experimental API usagefun createDateSource(): DateProvider { /* ... */ }fun getDate(): Date { val dateSource = createDateSource() // Also warning: experimental API usage // ...}
改进了推断递归泛型类型
在 Kotlin 和 Java 中,可以定义递归泛型类型,它在类型参数中引用自己。在 Kotlin 1.5.30 中,如果是递归泛型, Kotlin 编译器可以仅根据对应的类型参数的上界来推断类型参数。这使得使用递归泛型类型创建各种模式成为可能,这些模式在 Java 中经常用于创建构造者 Api。
// Kotlin 1.5.20val containerA = PostgreSQLContainer
你可以通过传入 -Xself-upper-bound-inference 或 -language-version 1.6 编译器选项来启用这些改进。
消除构建器推断限制
构建器(Builder)推断是一种特殊的类型推断,它允许你根据来自lambda参数内部其他调用的类型信息推断调用的类型参数。这在调用通用构建函数(如 buildList() 或 sequence())时很有用: buildList {add("string")} 。
在这样的lambda参数中,以前对于使用构建器推断试图推断的类型信息有一个限制。这意味着您只能指定它,而不能获取它。例如,如果没有显式指定类型参数,就不能在 buildList() 的lambda参数中调用get()。
Kotlin 1.5.30通过 -Xunrestricted-builder-inference编译器选项消除了这些限制。添加此选项以启用之前禁止在泛型构建函数的lambda参数内调用:
@kotlin.ExperimentalStdlibApival list = buildList { add("a") add("b") set(1, null) val x = get(1) if (x != null) { removeAt(1) }}@kotlin.ExperimentalStdlibApival map = buildMap { put("a", 1) put("b", 1.1) put("c", 2f)}
此外,您还可以使用 -language-version 1.6编译器选项启用此特性。
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~