Kotlin 1.2 新特性

点击关注异步图书,置顶公众号

每天与你分享IT好书 技术干货 职场知识



在Kotlin 1.1中,团队正式发布了JavaScript目标,允许开发者将Kotlin代码编译为JS并在浏览器中运行。在Kotlin 1.2中,团队增加了在JVM和JavaScript之间重用代码的可能性。现在,使用Kotlin编写的代码,可以在所有的应用程序中(包括后端,浏览器前端和Android移动应用程序)中重复使用。

想要体验Kotlin1.2新功能的同学,可以下载官方提供的IntelliJ IDEA 2017.3开发工具,或者升级老的IDE,当然也可以通过在线网站来体验。

跨平台

跨平台项目是 Kotlin 1.2 中的一个新的实验×××,它允许开发者从相同的代码库构建应用程序的多个层——后端、前端和Android应用程序,在这个跨平台方案中,主要包含三个模块。

  • 通用(common)模块:包含非特定于任何平台的代码,以及不附带依赖于平台的 API 实现的声明。
  • 平台(platform)模块:包含用于特定平台的通用模块中与平台相关声明的实现,以及其他平台相关代码。
  • 常规(regular)模块:针对特定平台,可以是平台模块的某些依赖,也可以是依赖的平台模块。

要从通用模块中调用特定于平台的代码,可以指定所需的声明:所有特定于平台的模块需要提供实际实现声明。而在为特定平台编译多平台项目时,会生成通用及特定平台相关部分的代码。可以通过 expected 以及 actual 声明来表达通用代码对平台特定部分的依赖关系。expected 声明指定了一个 API(类、接口、注释、顶层声明等)。actual 声明或是 API 的平台相关实现,或是在外部库中 API 现有实现的别名引用。下面是官方提供的相关例子:

通用模块

// expected platform-specific API:expect fun hello(world: String): Stringfun greet() {    // usage of the expected API:
    val greeting = hello("multi-platform world")
    println(greeting)
}
expect class URL(spec: String) {    open fun getHost(): String    open fun getPath(): String
}12345678910111213

JVM 平台代码

actual fun hello(world: String): String =    "Hello, $world, on the JVM platform!"// using existing platform-specific implementation:
actual typealias URL = java.net.URL12345

想要获取更多跨平台相关的信息,可以查看官方资料介绍。

请注意,目前跨平台项目只是一个实验×××,这意味着该功能已经可以使用,但可能需要在后续版本中更改设计

编译性能

在1.2的开发过程中,团队花了很多精力来优化编译系统,据官方提供的资料显示,与Kotlin 1.1相比,Kotlin带来了大约25%的性能提升,并且看到了可以进一步改进的巨大潜力,这些改进将在1.2.x更新中发布。 
下图显示了使用Kotlin构建两个大型JetBrains项目的编译时间差异。

语法与库优化

除了上面介绍的改动之外,Kotlin还在语法层面进行了部分改进,优化的部分有。

通过注解声明数组变量

自Kotlin1.2开始,系统允许通过注解声明数组参数,从而取代arrayOf函数的数组声明方式。例如:

@CacheConfig(cacheNames = ["books", "default"])
public class BookRepositoryImpl {
    // ...}1234

可见,新的数组参数声明语法依赖于注解方式。

关键字lateinit

lateinit 和lazy一样,是 Kotlin中的两种不同的延迟初始化技术。在Kotlin1.2版本中,使用lateinit修饰符能够用于全局变量和局部变量了,也就是说,二者都允许延迟初始化。例如,当lambda表达式在构造一个对象时,允许将延迟初始化属性作为构造参数传过去。

class Node<T>(val value: T, val next: () -> Node<T>)fun main(args: Array<String>) {    // A cycle of three nodes:
    lateinit var third: Node<Int>
    val second = Node(2, next = { third })
    val first = Node(1, next = { second })
    third = Node(3, next = { first })
    val nodes = generateSequence(first) { it.next() }
    println("Values in the cycle: ${nodes.take(7).joinToString { it.value.toString() }}, ...")
}123456789101112131415

运行上面的代码,输出结果如下:

Values in the cycle: 1, 2, 3, 1, 2, 3, 1, ...1

延迟初始化属性检测

通过访问属性的isInitialized字段,现在开发者可以检查一个延迟初始化属性是否已经初始化。

class Foo {
    lateinit var lateinitVar: String
    fun initializationLogic() {
        println("isInitialized before assignment: " + this::lateinitVar.isInitialized)
        lateinitVar = "value"
        println("isInitialized after assignment: " + this::lateinitVar.isInitialized)    
    }
}
fun main(args: Array<String>) {
    Foo().initializationLogic()
}1234567891011121314

运行结果为:

isInitialized before assignment: falseisInitialized after assignment: true12

内联函数默认参数

自1.2版本开始,Kotlin允许允许给内联函数的函数参数填写默认参数了。

inline fun <E> Iterable<E>.strings(transform: (E) -> String = { it.toString() }) = 
map { transform(it) }val defaultStrings = listOf(1, 2, 3).strings()val customStrings = listOf(1, 2, 3).strings { "($it)" } 
fun main(args: Array<String>) {    println("defaultStrings = $defaultStrings")
    println("customStrings = $customStrings")123456789

运行结果为:

defaultStrings = [1, 2, 3]customStrings = [(1), (2), (3)]12

变量类型推断

大家都知道,Kotlin的类型推断系统是非常强大的,现在Kotlin编译器也支持通过强制转换的信息,来推断出变量类型了。比如说,如果你在调用一个返回“T”的泛型方法时,并将它的返回值“T”转换为特定类型如“Foo”,编译器就会推断出这个方法调用中的“T”其实是“Foo”类型。

这个对安卓开发者而言尤其重要,因为自从API26(Android7.0)开始,findViewById变成了泛型方法,然后编译器也会正确分析该方法的调用返回值。

val button = findViewById(R.id.button) as Button1

智能转换

当一个变量为某个安全表达式(如校验非空)所赋值时,智能转换也同样运用于这个安全调用的接收者。

fun countFirst(s: Any): Int {    val firstChar = (s as? CharSequence)?.firstOrNull()    if (firstChar != null)    return s.count { it == firstChar } // 输入参数s被智能转换为CharSequence类型
    val firstItem = (s as? Iterable<*>)?.firstOrNull()    if (firstItem != null)    return s.count { it == firstItem } // 输入参数s被智能转换为Iterable<*>类型  
    return -1}fun main(args: Array<String>) {    val string = "abacaba"
    val countInString = countFirst(string)
    println("called on \"$string\": $countInString")    val list = listOf(1, 2, 3, 1, 2)    val countInList = countFirst(list)
    println("called on $list: $countInList")
}12345678910111213141516171819202122

运行结果为:

called on "abacaba": 4called on [1, 2, 3, 1, 2]: 212

另外,Lamba表达式同样支持对局部变量进行智能转换,前提是该局部变量只在Lamba表达式之前修改过。

fun main(args: Array<String>) {
    val flag = args.size == 0
    var x: String? = null
    if (flag) x = "Yahoo!"
    run {        if (x != null) {
            println(x.length) // x is smart cast to String
        }
    }
}12345678910111213

运行结果为:

6

foo的简写

为了简化调用成员的引用,现在可以不用this关键字,::foo而不用明确的接收者this::foo。这也使得可调用的引用在你引用外部接收者的成员的lambda中更方便。

弃用

Kotlin1.2版本也弃用了很多不合理的东西。

弃用:枚举条目中的嵌套类型

在枚举条目中,inner class由于初始化逻辑中的问题,定义一个非嵌套的类型已经被弃用了。这会在Kotlin 1.2中引起警告,并将在Kotlin 1.3中出错。

弃用:vararg单个命名参数

为了与注释中的数组文字保持一致,在命名形式(foo(items = i))中传递可变参数的单个项目已被弃用。请使用具有相应数组工厂功能的扩展运算符。

foo(items = *intArrayOf(1))1

在这种情况下,有一种优化可以消除冗余阵列的创建,从而防止性能下降。单参数形式在Kotlin 1.2中产生警告,并将被放在Kotlin 1.3中。

弃用:扩展Throwable的泛型内部类

继承的泛型类型的内部类Throwable可能会违反类型安全性,因此已被弃用,Kotlin 1.2中有警告,Kotlin 1.3中有错误。

弃用:只读属性的后台字段

field = …已经废弃了在自定义获取器中分配只读属性的后台字段,Kotlin 1.2中有警告,Kotlin 1.3中有错误。

标准库

Kotlin标准库与拆分包

Kotlin标准库现在完全兼容Java 9模块系统,该系统禁止拆分包(多个jar文件在同一个包中声明类)。为了支持这一点,新的文物kotlin-stdlib-jdk7 和kotlin-stdlib-jdk8介绍,取代旧的kotlin-stdlib-jre7和kotlin-stdlib-jre8。

为确保与新模块系统的兼容性,Kotlin做出的另一个更改是将kotlin.reflect从kotlin-reflect库中移除。如果您正在使用它们,则需要切换到使用kotlin.reflect.full软件包中的声明,这是自Kotlin 1.1以来支持的声明。

窗口,分块,zipWithNext

为新的扩展Iterable,Sequence以及CharSequence覆盖这些用例如缓冲或批处理(chunked),滑动窗口和计算滑动平均(windowed),和随后的项目的处理对(zipWithNext)。

fun main(args: Array<String>) {
    val items = (1..9).map { it * it }
    val chunkedIntoLists = items.chunked(4)
    val points3d = items.chunked(3) { (x, y, z) -> Triple(x, y, z) }
    val windowed = items.windowed(4)
    val slidingAverage = items.windowed(4) { it.average() }
    val pairwiseDifferences = items.zipWithNext { a, b -> b - a }
    println("items: $items")
    println("chunked into lists: $chunkedIntoLists")
    println("3D points: $points3d")
    println("windowed by 4: $windowed")
    println("sliding average by 4: $slidingAverage")
    println("pairwise differences: $pairwiseDifferences")
}123456789101112131415161718

fill, replaceAll, shuffle/shuffled

为了操纵列表,Kotlin加入了一组扩展函数:fill,replaceAll和shuffle对MutableList,shuffled用于只读List。

fun main(args: Array<String>) {
    val items = (1..5).toMutableList()    items.shuffle()
    println("Shuffled items: $items")    items.replaceAll { it * 2 }
    println("Items doubled: $items")    items.fill(5)
    println("Items filled with 5: $items")
}12345678910111213

运行结果为:

Shuffled items: [5, 3, 1, 2, 4] 
Items doubled: [10, 6, 2, 4, 8] 
Items filled with 5: [5, 5, 5, 5, 5]

数学运算

为了满足一些特殊的需求,Kotlin 1.2添加了一些常见的数学运算API。

常量:PI和E;

三角函数:cos,sin,tan和它们的反:acos,asin,atan,atan2,

双曲:cosh,sinh,tanh和它们的反:acosh,asinh,atanh

求幂:pow(扩展函数),sqrt,,hypot ;expexpm1

对数:log,log2,log10,ln,ln1p,

四舍五入: ceil,floor,truncate,round(半连)的功能; 
roundToInt,roundToLong(半整数)扩展函数;

符号和绝对值: abs和sign功能; absoluteValue和sign扩展属性; withSign 扩展功能;max和min两个价值观;

二进制表示: ulp 扩展属性; nextUp,nextDown,nextTowards扩展函数;toBits,toRawBits,Double.fromBits(这些是在kotlin包)。

正则表达式可序列化

现在,Kotlin可以使用Serializable来序列化正则表达式的层次结构。

JVM

构造函数调用规范化

自1.0版以来,Kotlin支持复杂控制流的表达式,例如try-catch表达式和内联函数调用。但是,如果构造函数调用的参数中存在这样的表达式时,一些字节码处理工具不能很好地处理这些代码。为了缓解这种字节码处理工具的用户的这个问题,我们添加了一个命令行选项(-Xnormalize-constructor-calls=MODE),它告诉编译器为这样的结构生成更多的类Java字节码。

其中,这里的MODE有以下情况:

disable (默认) - 以和Kotlin 1.0和1.1相同的方式生成字节码;

enable - 为构造函数调用生成类似Java的字节码。这可以改变类加载和初始化的顺序;

preserve-class-initialization -为构造函数调用生成类似Java的字节码,确保保持类的初始化顺序。这可能会影响应用程序的整体性能;只有在多个类之间共享一些复杂的状态并在类初始化时更新时才使用它。

Java默认方法调用

在Kotlin 1.2之前,接口成员在针对JVM 1.6的情况下重写Java默认方法会在超级调用上产生一个警告:Super calls to Java default methods are deprecated in JVM target 1.6. Recompile with ‘-jvm-target 1.8’。在Kotlin 1.2中,会出现一个错误,因此需要使用JVM target 1.8来编译这些代码。

x.equals(null)

调用x.equals(null)上被映射到Java原始(平台类型Int!,Boolean!,Short!, ,Long!,Float!,Double!)Char!返回不正确true时x为空。从Kotlin 1.2开始,调用x.equals(…)一个平台类型的null值会抛出一个NPE (但是x == …不会)。

要返回到1.2之前的行为,请将该标志传递-Xno-exception-on-explicit-equals-for-boxed-null给编译器。

内联扩展空修复

在以前的版本中,在平台类型的空值上调用的内联扩展函数没有检查接收器是否为null,并因此允许null转义到其他代码中。Kotlin 1.2中强制执行此检查,如果接收方为空,则抛出异常。

JavaScript

TypedArrays支持

JS类型的数组支持将Kotlin原始数组(例如IntArray,DoubleArray)转换为JavaScript类型的数组,这以前是可选入功能,默认情况下已启用。

除此之外,Kotlin的编译器现在提供一个将所有警告视为错误的选项。使用-Werror命令行,或者修改如下配置:

compileKotlin {
    kotlinOptions.allWarningsAsErrors = true}123

想要了解更多的官方知识介绍,请查看:Kotlin 1.2带来了什么新特性

本文摘自异步社区,作者: xiangzhihong 作品:《Kotlin 1.2 新特性》

推荐阅读

2018年5月新书书单(文末福利)

2018年4月新书书单

异步图书最全Python书单

一份程序员必备的算法书单

第一本Python神经网络编程图书

长按二维码,可以关注我们哟

每天与你分享IT好文。

在“异步图书”后台回复“关注”,即可免费获得2000门在线视频课程;推荐朋友关注根据提示获取赠书链接,免费得异步e读版图书一本。赶紧来参加哦!

点击阅读原文,查看更多

阅读原文

原文地址:http://blog.51cto.com/13127751/2114883

时间: 2024-12-19 08:11:03

Kotlin 1.2 新特性的相关文章

macOS&&IntelliJ IDEA-IntelliJ IDEA介绍以及IntelliJ IDEA 2019.3新特性

macOS&&IntelliJ IDEA-IntelliJ IDEA介绍以及IntelliJ IDEA 2019.3新特性 macOS&&IntelliJ IDEA JetBrains公司介绍 在介绍IntelliJ IDEA之前,先介绍IntelliJ IDEA这个产品的生产厂商-JetBrains 目前JetBrains官网部分内容支持中文访问,只需要在域名后面加上/zh-cn即可. 它是来自于捷克的软件开发公司,旗下有诸多的产品,涵盖了主流的语言和技术 Intelli

Java 14 有哪些新特性?

记录为 Java 提供了一种正确实现数据类的能力,不再需要为实现数据类而编写冗长的代码.下面就来看看 Java 14 中的记录有哪些新特性. 作者 | Nathan Esquenazi 译者 | 弯月,责编 | 郭芮 以下为译文: Java 14 即将在 2020 年 3 月正式发布. Java 以 6 个月作为新版本的发布周期,和之前的版本发布一样,JDK 14 预计将在语言本身和 JVM 级别上带来一些新特性. 如果我们看一下特性列表,我们会注意到一些开发者非常期待的语言特性:记录 (rec

web新特性 之 WebSocket

详情参见:你真的了解WebSocket吗?     WebSocket系列教程   HTML5新特性之WebSocket WebSocket协议是基于TCP的一种新的协议.WebSocket最初在HTML5规范中被引用为TCP连接,作为基于TCP的套接字API的占位符.它实现了浏览器与服务器全双工(full-duplex)通信.其本质是保持TCP连接,在浏览器和服务端通过Socket进行通信. 服务端与客户端的连接不断开,实现全双工的操作.及服务端或是客户端都会给对方发送消息. WebSocke

Java精品高级课,架构课,java8新特性,P2P金融项目,程序设计,功能设计,数据库设计,第三方支付,web安全,视频教程

36套精品Java架构师,高并发,高性能,高可用,分布式,集群,电商,缓存,性能调优,设计模式,项目实战,P2P金融项目,大型分布式电商实战视频教程 视频课程包含: 高级Java架构师包含:Spring boot.Spring  cloud.Dubbo.Elasticsearch,Redis.ActiveMQ.Nginx.Mycat.Spring.MongoDB.ZeroMQ.Git.Nosql.Jvm.Mecached.Netty.Nio.Mina.java8新特性,P2P金融项目,程序设计,

Atitit js es5 es6新特性 attilax总结

1.1. JavaScript发展时间轴:1 1.2. 以下是ES6排名前十的最佳特性列表(排名不分先后):1 1.3. Es6 支持情况 基本chrome ff 360se8全面支持了2 2. ECMAScript 2015(ES6)的十大特征 – WEB前端开发 - 专注前端开发,关注用户体验.html2 1.1. JavaScript发展时间轴: 1.1995:JavaScript诞生,它的初始名叫LiveScript. 2.1997:ECMAScript标准确立. 3.1999:ES3出

CSS3的新特性 行内盒子before和after

CSS3的新特性 1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>before after</title> 6 <style type="text/css"> 7 /*在DIV1盒子内部前面*/ 8 #div1:before{ 9 width: 100p

Xcode And iOS9新特性

Xcode And iOS9 1. Xcode7 新特性 > 可直接在真机上运行自己的应用,只需要有苹果账号,无需购买苹果开发者账号. > 可设置在出现 EXC_BAD_ACCESS 错误时,显示更详细的错误信息. 设置方式:XCode->Product->Scheme->Edit Scheme 左侧选择“Run” 右侧选择“Diagnostics(诊断)” 在“Runtime Sanitization(运行时净化处理)” 勾选“Enable Address Sanitize

Atitit.业务系统的新特性&#160;开发平台&#160;新特性的来源总结

Atitit.业务系统的新特性 开发平台 新特性的来源总结 1.1. 语言新特性(java c# php js python lisp c++ oc swift ruby  go dart1 1.2. 流行lib.frmawork  新特性 jdk clr framework 新特性 (jq   Servlet2 1.3. Ide 新特性( eclipse vs netbea jetbrain2 1.4. Vm  新特性 clr  jvm(jvm好像没有独立的版本号,继承在jdk里面2 1.5.

Atitit.mysql&#160;5.0&#160;5.5&#160;&#160;5.6&#160;5.7&#160;&#160;新特性&#160;新功能

Atitit.mysql 5.0 5.5  5.6 5.7  新特性 新功能 1. MySQL  5.6    5 大新特性1 1.1. 优化器的改进1 1.2. InnoDB 改进1 1.3. 使用 memcached API 直接访问 NoSQL2 1.4. 更好的复制2 1.5. Performance Schema2 2. MySQL 5.7.62 2.1. 内建中文全文索引2 2.2. 多主复制2 2.3. other2 3. 参考2 1. MySQL  5.6    5 大新特性 M