Kotlin 1.2 新特性-阿里云开发者社区

开发者社区> 异步社区> 正文

Kotlin 1.2 新特性

简介: 在Kotlin 1.1中,团队正式发布了JavaScript目标,允许开发者将Kotlin代码编译为JS并在浏览器中运行。在Kotlin 1.2中,团队增加了在JVM和JavaScript之间重用代码的可能性。
+关注继续查看

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

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


9ccc0ca9gy1fr69wv92r6j20u00f0dh2.jpg

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

9ccc0ca9gy1fr6aw6wudqj20hs094dgf.jpg

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

跨平台

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

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

9ccc0ca9gy1fr6awzij67j20hs0aj3yq.jpg

​要从通用模块中调用特定于平台的代码,可以指定所需的声明:所有特定于平台的模块需要提供实际实现声明。而在为特定平台编译多平台项目时,会生成通用及特定平台相关部分的代码。可以通过 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项目的编译时间差异。 

9ccc0ca9gy1fr6ayyrzqqj20hs07ddfx.jpg

语法与库优化

除了上面介绍的改动之外,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 新特性》​

9ccc0ca9gy1fr5d068t8xg20hs01pt93.gif

​推荐阅读

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

2018年4月新书书单

异步图书最全Python书单

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

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

9ccc0ca9gy1fqyf4q8tctj209k09k744.jpg

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

每天与你分享IT好文。


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

点击阅读原文,查看更多

阅读原文

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
阿里云服务器怎么设置密码?怎么停机?怎么重启服务器?
如果在创建实例时没有设置密码,或者密码丢失,您可以在控制台上重新设置实例的登录密码。本文仅描述如何在 ECS 管理控制台上修改实例登录密码。
7765 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,大概有三种登录方式:
2615 0
阿里云服务器ECS远程登录用户名密码查询方法
阿里云服务器ECS远程连接登录输入用户名和密码,阿里云没有默认密码,如果购买时没设置需要先重置实例密码,Windows用户名是administrator,Linux账号是root,阿小云来详细说下阿里云服务器远程登录连接用户名和密码查询方法
10123 0
阿里云服务器端口号设置
阿里云服务器初级使用者可能面临的问题之一. 使用tomcat或者其他服务器软件设置端口号后,比如 一些不是默认的, mysql的 3306, mssql的1433,有时候打不开网页, 原因是没有在ecs安全组去设置这个端口号. 解决: 点击ecs下网络和安全下的安全组 在弹出的安全组中,如果没有就新建安全组,然后点击配置规则 最后如上图点击添加...或快速创建.   have fun!  将编程看作是一门艺术,而不单单是个技术。
9500 0
阿里云服务器安全组设置内网互通的方法
虽然0.0.0.0/0使用非常方便,但是发现很多同学使用它来做内网互通,这是有安全风险的,实例有可能会在经典网络被内网IP访问到。下面介绍一下四种安全的内网互联设置方法。 购买前请先:领取阿里云幸运券,有很多优惠,可到下文中领取。
11713 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,阿里云优惠总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系.
11134 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,云吞铺子总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系统盘、创建快照、配置安全组等操作如何登录ECS云服务器控制台? 1、先登录到阿里云ECS服务器控制台 2、点击顶部的“控制台” 3、通过左侧栏,切换到“云服务器ECS”即可,如下图所示 通过ECS控制台的远程连接来登录到云服务器 阿里云ECS云服务器自带远程连接功能,使用该功能可以登录到云服务器,简单且方便,如下图:点击“远程连接”,第一次连接会自动生成6位数字密码,输入密码即可登录到云服务器上。
21010 0
+关注
异步社区
异步社区(www.epubit.com)是人民邮电出版社旗下IT专业图书旗舰社区,也是国内领先的IT专业图书社区,致力于优质学习内容的出版和分享,实现了纸书电子书的同步上架,于2015年8月上线运营。公众号【异步图书】,每日赠送异步新书。
12049
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载