Kotlin到底是什么呢?它是一个目标为Java平台上的新的编程语言。它是简洁、安全、实用和可以跟Java互操作。它能用到所有Java可以用到的地方: 服务端开发,Android应用开发,或者更多。Kotlin可以和所有存在的Java库和框架一起良好工作,有Java一样的效率。
1 体验Kotlin
用一个小例子来Kotlin来看是什么样子的。这个例子定义了一个Person类、创建人的集合,找到年龄最大的那个,然后打印结果。
定义"data"类Person,有两个属性name和age,age属性可空类型Int?,默认为null
data class Person(val name: String, val age: Int? = null)
顶层函数main里面,定义了人的列表,忽略了Alice的age属性,所以设置为默认属性为null值。然后用maxBy函数找到年龄最大的那个人。lambda表达式传递给函数,lambda接受一个默认名字为it的一个参数。如果age属性为null,埃尔维斯操作子(Elvis operator ?:)返回零。因为Alice的age没有指定,所以埃尔维斯操作子替换age为零。所以Bob赢得了这个奖:年龄最大的人。
fun main(args: Array) {
val persons = listOf(Person("Alice"), Person("Bob", age = 29))
val oldest = persons.maxBy { it.age ?: 0 }
println("The oldest is: $oldest")
}
// The oldest is: Person(name=Bob, age=29)
2 Kotlin的主要特性
2.1 目标平台: 服务器端、Android、Java运行的任何地方
Kotlin 可以用在Java运行的任何地方,从智能卡到谷歌、推特、领英和其他的互联网级别的公司的数据中心。Kotlin最广泛的应用领域为:
- 构建服务端代码(典型的为,网络应用的后端)
- 构建运行在Android设备里面的移动应用
另外在其他环境中的应用
- 比如,在IOS设备中,通过因特尔的多系统引擎https://software.intel.com/en-us/multi-os-engine,可以运行Kotlin代码;
- 再比如,可以和TornadoFXhttps://github.com/edvin/tornadofx和JavaFX一起构建桌面应用
在Java外,Kotlin可以编译成JavaScript,但是现在JetBrains还在探索和原型中。在以后的版本中会支持更多的平台。
2.2 静态的类型
和Java一样,Kotlin也是静态编程语言。这意味着,每个类型的表达式在编译阶段就确定了。这个与动态编程语言相反,比如在JVM运行的Groovy和JRuby,可以定义变量和函数可以存储或者返回任何类型的数据,在运行的时候解析。
和Java不一样的是,Kotlin可以在上下文中自动决定一个变量的类型,这允许忽略声明时候的类型,这叫类型推导。如下,自动推导为Int类型。
val x = 1
以下是静态类型的优势
- 性能--- 方法调用更快,因为不要在运行时确定哪个方法需要调用。
- 可靠--- 编译器会验证每个程序的正确性,所以在运行的时候更少的崩溃。
- 可维护--- 处理不熟悉代码更容易,因为你可以看到你处理的代码的什么目标。
- 工具支持--- 可靠的重构,精确的代码补全和其他的IDE特性
由于类型推导,静态类型的繁琐消失了,因为不要显示的声明类型。Kotlin类型系统和Java里面的概念很相像,比如类,接口,泛型。但是Kotlin有些新东西。最重要的是可空类型(nullable type),让你写更可靠的程序,可以在编译的时候发现NPE;还有就是Kotlin支持函数类型(function types)
2.3 函数式和面向对象式
Java开发者熟悉面向对象的编程,不熟悉函数式编程,它的关键概念如下:
- 一等函数--- 把函数(一些行为)当成值,可以存储子变量中,可以当成参数传递,在其他的函数返回。
- 不可变性--- 对象在创建后不能改变它的状态
- 无副作用--- 给定同个输入,纯函数返回相同的结果,不会改变另外的对象的状态,也外部世界交互。
函数式编程有什么好处呢?第一,简洁,相对于命令式,函数式代码更优雅和简明,因为把函数当成值给你抽象的力量。假设,你有两个相似的代码片段实现相似的任务。你可以抽取相同的逻辑到一个函数,把不同的部分作为函数的参数。这些参数本身就是函数,你可以用lambda表达式作为匿名函数。
fun findAlice() = findPerson { it.name == "Alice" }
fun findBob() = findPerson { it.name == "Bob" }
第二,多线程安全,多线程程序最多的错误,在于没有正确的同步下,改变了多线程下同一个数据。如果你用不可变的数据结构和纯函数,不安全的更改就不会发生。
最后,容易测试,没有副作用的函数可以独立的测试,不要太多的设置依赖的整个环境
一般地讲,函数式类型可以在包含Java的所有编程语言中使用。但是不是所有的语言提供句法和库支持来轻松使用。比如,Java8之前版本就不支持。Kotlin一开始就有丰富的功能集来支持函数式编程。这包括:
- 函数类型--- 让函数接受其他的函数作为参数或者返回其他的函数
- Lambda表达式--- 让你用最少的样板代码来传递一段代码
- 数据类型--- 提供简洁的语法来创建不变的值实例
- 标准库中丰富的API集,以函数式类型,处理实例和集合
2.4 免费和开源代码
Kotlin语言,包括编译器、库和相关的工具,是完全开源的和任何目的的免费使用,可以Apache2许可下取得。在Github上公开开发http://github.com/ jetbrains/ kotlin,欢迎社区贡献代码。有三种开源IDE开发Kotlin代码: IntelliJ社区版本, Android Studio, 和Eclipse。
3 kotlin应用
3.1服务器端的Kotlin
服务器端编程是相当宽的概念,它不止包括如下:
- 网络应用,返回HTML页面到浏览器
- 移动应用的后端,通过HTTP暴露JSON的API
- 微服务,通过RPC协议和其他的微服务通讯
Java能积累了一大堆框架和技术。Kotlin最大的优势是,能和Java存在的Java代码互操作。不管是写一个新部件还是移植已经存在的服务,Kotlin非常适合。扩展新的Java类,还是注释类的方法或者域,你不会遇见任何问题。优势是,系统的代码更加紧凑,更加可靠和更容易维护。
同时,Kotlin发展了一些开发这些系统的新技术。比如,它支持Builder模式,让你用简洁的语法构建一个实例图谱,同时保持抽象和代码重用。一个最简单用例是HTML生成库,它用简洁和类型安全的解决方案,代替了一个外部模板语言,下面就是个例子:
fun renderPersonList(persons: Collection) =
createHTML().table {//HTML标签
for (person in persons) {//一般情形的回圈
tr {//HTML标签
td { +person.name } //HTML标签
td { +person.age }
}
}
}
}
另外的例子是,你用Kotlin简洁和整洁的DSL的持久化框架。比如Exposed框架https://github.com/jetbrains/exposed,提供了容易读的DSL,完全用Kotlin代码和静态检查,来描述SQL数据库结构和增删查改。这是一个小例子:
object CountryTable : IdTable() { //描述一个数据库表
val name = varchar("name", 250).uniqueIndex()
val iso = varchar("iso", 2).uniqueIndex()
}
class Country(id: EntityID) : Entity(id) { //创建一个相应数据库entity的类
var name: String by CountryTable.name
var iso: String by CountryTable.iso
}
val russia = Country.find {//用纯粹的Kotlin代码查询这个数据库
CountryTable.iso.eq("ru")
}.first()
println(russia.name)
3.2 Android上的Kotlin
Kotlin语言特性,和在Android框架上的一个特别的插件编译器,把Android开发变成一个更加有效率和愉快的经历。一般的开发任务,比如为控件添加监听器,或者绑布局元素到域,可以用更加少的代码,或者根本不用代码(编译器为你生产)。Anko库https://github.com/kotlin/anko,也是由Kotlin团队构建,用来改善开发经历:在许多Android标准API上添加Kotlin友好的适配器。
以下是Anko的一个简单例子,把这段代码放在Activity中,一个简单的Android应用就好了:
verticalLayout {
val name = editText() 一个简单的文本域
button("Say Hello") { //当点击时,按钮显示文本域的值
onClick { toast("Hello, ${name.text}!") } //一个简洁的API,添加一个监听器和显示一个toast
}
}
另外一个使用Kotlin的优势是更好的应用可靠性。如果你熟悉Android应用开发,你一定不会陌生Unfortunately, Process Has Stopped dialog,这个就是应用抛出了一个未经处理的异常--通常是NullPointerException。Kotlin类型系统,更加精确的追踪null值,使得NPE更少发生。
同时,Kotlin完全兼容Java6,不会带来兼容问题。至于性能,使用Kotlin不会带来任何劣势。Kotlin编译器生成的代码和一般的Java代码一样有效率。Kotlin的运行时的代码相当小,所以你不会见到一个编译的应用包大小的增大。kotlin标准库函数将会内联lambda,内联的lambda是的没有新的实例创建,应用也不会遭受到额外的GC停滞。
4 Kotlin的哲学
当我们讲到Kotlin,我们愿意说是实用、简洁和安全的语言,同时强调互操作性。
4.1 实用
实用意味着Kotlin是一个设计成解决现实世界问题的实用语言。这个设计是以多年来构建大规模系统的工业经验为基础的;它的功能是为解决众多软件开发者遇见的问题而挑选的。再者,Jetbrains团队和社区多年使用Kotlin早期的各种版本,他们的反馈塑造了这个语言的早期版本。
Kotlin不是一个研究语言,我们不会尝试编程语言设计的艺术和探索计算机科学的创新思想。相反,只有有可能,我们依赖一些已经在其他语言证明比较成功的功能和解决方案,这减少了语言的复杂性,也使得依赖熟悉的概念来更容易的学习。
此外,Kotlin不会强制用任何特别的编程风格和范式。一开始学习这个语言,你可以用熟悉的Java的风格和技巧。然后你逐渐会发现Kotlin更加强大的特性,然后学习在代码中应用他们,使得代码更加简洁和符合语言习惯。
Kotlin的实用性的另外一个方面是,关注工具。开发者效率来说,一个智能的开发环境与一个好的语言同等重要。所以,不会把IDE支持作为事后的想法。Kotlin来说,IntelliJ IDEA插件和编译器的开发步调一致。
4.2 简洁
众所周知,读代码比写代码花的时间更多。所以代码越简单和简洁,你理解的越快。如果语言的语法清晰的表达了代码的意图,而且指定这个意图这么完成的样板代码不会掩盖它,这就说,语言是简洁的。
Kotlin中,相当多的标准Java样板代码,比如getter、setter和构造子的参数赋值到域,在Kotlin是隐藏的,不会使你的源代码凌乱。另外一个合理的代码是,不需要写显式的代码来执行一些通用的任务,比如,在一个集合中定位一个元素。Kotlin有丰富的标准库函数来替代冗长重复的库函数调用代码。Kotlin支持lambda表达式,这使得传递一小段代码给库函数更加容易。
同时,Kotlin不会把源代码压缩成最少字符。比如,尽管Kotlin支持操作子重载,但是用户不能定义自己的操作子。所以,库的开发者不能用含义模糊的标点符号替代方法名。
4.3 安全
一般,说一个编程语言是安全的,意味着设计阻止了一些类型的错误。当然,这没有绝对性。阻止错误总是要代价的。所以,在你获得的安全性等级和效率损失之间,总有权衡。
在Kotlin中,我们尝试一个比Java高的安全等级,但是用非常小的整理代价。kotlin不用指明所有的类型声明,但是编译器可以自动推导出它的类型。此外,在编译阶段检查来阻止更多的错误,而不是在运行阶段失败。Kotlin类型系统追踪值能或者不能为空,从而禁止导致运行时的NPE。一个额外的代码是很小的,只要在可空的类型最后标记一个问号
val s: String? = null //May be null
val s2: String = ""//May not be null
此外,Kotlin提供一些处理可空数据的便利方法。Kotlin避免的另外一种异常是ClassCastException。Java的开发者一般不会检查类型,因为类型名字必须在检查和接下来的强转中。在Kotlin中,检查和强转合并到一个操作:
if (value is String) //Checks the type
println(value.toUpperCase()) //Uses the method of the type
4.4 互操作性
“我能用已经存在的库吗?”,Kotlin说,“当然可以”。不管库需要你用什么样的API,你可以在Kotlin中使用。你可以调用Java的方法,扩展Java的类,和实现接口,应用Java注解到Kotlin类中,等等。
不像其他的JVM语言,Kotlin在互操作性进了一步,在Java中可以调用Kotlin代码。也没什么技巧:Kotlin类和方法就像正常的Java类和方法一样可以调动。这使得在你项目中灵活使用混合的Kotlin和Java。
Kotlin关注的互操作性的另外一个领域是,最大程度的使用已经存在的Java库。比如,Kotlin没有自己的集合库,它完全依赖Java标准库的类,而且为了便利,用额外的函数来扩展。当你Kotlin中调用Java API,你不需要包装或者变换实例,反之亦然。
Kotlin工具也提供了跨语言项目的完整支持。可以编译任意Java和Kotlin源文件。IDE功能不同语言也适用:
- Java和Kotlin源文件的自由导航
- 混合语言项目的调试,不同语言的代码一步步跟踪
- Java方法的重构,Kotlin代码的正确更新,或者相反
5 使用kotlin工具
讨论下,编译过程是怎么工作的,为你提供了什么工具。关于怎么设置环境,请参考Kotlin网页的“教程” https://kotlinlang.org/docs/tutorials
5.1 编译Kotlin代码
Kotlin源码一般存储在扩展名为.kt的文件中。编译器分析源码,生成。class文件,就像Java编译器一样。生成的.class然后用你应用类型的标准过程打包执行。最简单的情形,在命令行中用kotlinc命令编译代码,用Java命令执行代码。
kotlinc
简单描述Kotlin的构建过程如下:
Kotlin编译器编译的代码依赖Kotlin运行时库。这个库包含了定义kotlin自己的标准库类和扩展,这些类和扩展是加入到标准Java API中。运行时库需要和你的应用一起发布。
在实际事例中,你会使用构建系统,比如,Maven,Gradle或者Ant来编译代码。Kotlin兼容这些构建系统。所有的构建系统都支持混合语言项目,在同一个代码库中同同时编译Kotlin和Java。此外,Maven和Gradle把Kotlin运行时库作为应用的一个依赖。
5.2 IntelliJ IDEA 和 Android Studio的插件
IntelliJ IDEA的kotlin插件和语言一起开发的。这个IDE提供了开发Kotlin的网站工具集。Kotlin插件包含在IntelliJ IDEA 15或者更新的版本,不需要额外的设置。你可以用IntelliJ IDEA社区版本或者IntelliJ IDEA Ultimate。如果你使用Android Studio,你可以从插件管理器中安装插件。
5.3 交互式shell
如果你想尝试一小段Kotlin代码,你可以用交互式shell(或者叫REPL),在REPL,你可以逐行敲Kotlin代码,可以立即看见执行结果。你可以运行不带参数的kotlinc命令,或者用IntelliJ IDEA插件的响应目录上的选项。
5.4 Eclipse插件
Eclipse的kotlin插件提供了IDE基本功能,比如导航和代码补全。这个插件可以在Eclipse市场上获得。用目录上的帮助>Eclipse市场,搜索Kotlin。
5.5 在线playground
最简单的使用Kotlin方法不需要安装和配置。在http://try.kotl.in,你可以找到在线playground,你可以编写、编译和运行小段Kotlin程序。playground有代码例子来演示Kotlin功能,也包括本书的例子和一系列交互学习的练习。
5.6 Java-to-Kotlin转换器
快速学习一门新语言是不会不费力气的。幸运的是,我们构建了一个友好的小小的快捷方式,让你依赖已有的Java知识来加快学习。这个工具就是Java-to-Kotlin自动转换器。
当你学习Kotlin,转换器可以帮助你表达一些事情,即使你不知道确切的语法。你可以用Java写响应的片段,然后拷贝到Kotlin文件中,这个转换器可以自动的转换到Kotlin。虽然结果不是最符合语言习惯的,但是代码能工作。