Kotlin 初体验:主要特征与应用

管理员账号

2017-08-15

小编说:Kotlin 是一种针对 Java 平台的新编程语言。它简洁、安全、务实,并且专注于与 Java 代码的互操作性。它几乎可以用在现在 Java 使用的任何地方 :服务器端开发、Android 应用,等等。本文我们将详细地探讨 Kotlin 的主要特征。本文选自《Kotlin实战》。

Kotlin初体验

让我们从一个小例子开始,来看看 Kotlin 代码长什么样子。这个例子定义了一个 Person 类来表示“人”,创建一个“人”的集合,查找其中年纪最大的人,并打印结果。尽管这是非常小的一段代码,从中也可以看到 Kotlin 许多有趣的特性。

我们对其中的一些特性做了标记,以便你可以方便地在本书后续的内容中找到它们。

代码简要地进行了解释,但是如果有些内容你现在还无法理解,请不要担心,稍后我们会详细讨论。

如果你想尝试运行这个例 子,最简单的方法是使用 http://try.kotl.in 的在线 Playground。输入示例代码并单击 Run 按钮,代码将会执行。

代码清单 1.1 Kotlin 初体验

你声明了一个简单的数据类,它包括了两个属性:name和age。age属性默认为null(如果没有指定)。在创建“人”的列表时,你省略了Alice的年龄,所以这里年龄使用了默认值null。然后你调用了maxBy函数来查找列表中年纪最大的那个“人”。传递给这个函数的lambda表达式需要一个参数,使用it作为这个参数的默认名称。如果age属性为null,Elvis运算符(?:)会返回零。因为Alice的年龄没有指定,Elvis运算符使用零代替了它,所以Bob幸运地成了年纪最大的人。

喜欢这样的代码吗 ? 继续读下去,你将会学习到更多,并成为一名 Kotlin 专家。我们希望不久之后,在你自己的项目中也能看到这样的代码,而不只是在书上。

Kotlin的主要特征

你大概已经知道了 Kotlin 是一种怎样的语言,让我们更加深入地了解一下它的关键属性。首先,我们来看看你能用 Kotlin 创造哪些种类的应用程序。

目标平台 :服务器端、Android 及任何 Java 运行的地方

Kotlin 的首要目标是提供一种更简洁、更高效、更安全的替代 Java 的语言,并且适用于现今使用 Java 的所有环境。Java 是一门非常受欢迎的语言,它广泛地应用于不同的环境 :小到智能卡 (JavaCard 技术 ),大到 Google、Twitter、LinkedIn 和其他这种规模的互联网公司运行的最大的数据中心。在这些地方,使用 Kotlin 可以帮助开发者在实现目标的同时减少代码并避免麻烦。

Kotlin 最常见的应用场景有 :

编写服务器端代码(典型的代表是 Web 应用后端)

创建 Android 设备上运行的移动应用

但 Kotlin 还有其他用武之地。例如,可以使用 Intel Multi-OS Engine((https:// software.intel.com/en-us/multi-os-engine) 让 Kotlin 代码运行在 iOS 设备上。还可以 使用 Kotlin 和 TornadoFX(https://github.com/edvin/tornadofx) 以及 JavaFX(http://mng.bz/500y) 一起来构 建桌面应用程序。

除了 Java 之外,Kotlin 还可以编译成 JavaScript,允许你在浏览器中运行 Kotlin 代码。但截止本书撰写时,对 JavaScript 的支持仍在 JetBrains 内部探索并进行原型 开发,这超出了本书的范围,而其他一些平台也在考虑支持 Kotlin 的未来版本。

正如你所看到的,Kotlin 的目标平台是相当广泛的。Kotlin 并没有被限制在单 一的问题域,也没有被限制在解决软件开发者面临的某一类型的挑战。相反,对所 有开发过程中涌现的任务,Kotlin 都提供了全面的生产力提升。它借助支持特定领 域或编程范式的库,提供了卓越的集成水准。接下来让我们来看看 Kotlin 作为一种 编程语言的关键特质。

静态类型

Kotlin 和 Java 一样是一种静态类型的编程语言。这意味着所有表达式的类型在 编译期已经确定了,而编译器就能验证对象是否包含了你想访问的方法或者字段。

这与 动态类型 的编程语言形成了鲜明的对比,后者在 JVM 上的代表包括 Groovy 和 JRuby。这些语言允许你定义可以存储任何数据类型的变量,或者返回任 何数据类型的函数,并在运行时才解析方法和字段引用。这会减少代码量并增加创 建数据结构的灵活性。但它的缺点是,在编译期不能发现像名字拼写错误这样的问题,继而导致运行时的错误。

另一方面,与 Java 不同的是,Kotlin 不需要你在源代码中显式地声明每个变量 的类型。很多情况下,变量类型可以根据上下文来自动判断,这样就可以省略类型声明。这里有一个可能是最简单的例子 :

val x = 1

在声明这个变量时,由于变量初始化为整型值,Kotlin 自动判断出它的类型是 Int。编译器这种从上下文推断变量类型的能力被称作类型推导。

下面罗列了一些静态类型带来的好处 :

性能——方法调用速度更快,因为不需要在运行时才来判断调用的是哪个方法。

可靠性——编译器验证了程序的正确性,因而运行时崩溃的概率更低。

可维护性——陌生代码更容易维护,因为你可以看到代码中用到的对象的类型。

工具支持——静态类型使 IDE 能提供可靠的重构、精确的代码补全以及其他 特性。

得益于 Kotlin 对类型推导的支持,你不再需要显式地声明类型,因此大部分关 于静态类型的额外冗长代码也就不复存在了。

当你检视 Kotlin 类型系统的细节时,你会发现许多熟悉的概念。类、接口以及 泛型和 Java 非常接近,所以大部分的 Java 知识可以很容易地转移到 Kotlin。然而, 也会有一些新概念出现。

其中最重要的概念是 Kotlin 对可空类型的支持,通过在编译期检测可能存在的 空指针异常,它让你可以写出更可靠的程序。

另一个 Kotlin 类型系统的新概念是对函数类型的支持。要搞清楚这一点,我们 先要了解函数式编程的主要思想,以及 Kotlin 是如何支持这种编程风格的。

函数式和面向对象

作为一个 Java 开发者,你一定对面向对象编程的核心概念烂熟于胸,但函数式 编程对你来说却可能很新鲜。函数式编程的核心概念如下 :

头等函数——把函数(一小段行为)当作值使用,可以用变量保存它,把它 当作参数传递,或者当作其他函数的返回值。

不可变性——使用不可变对象,这保证了它们的状态在其创建之后不能再变 化。

无副作用——使用的是纯函数。此类函数在输入相同时会产生同样的结果, 并且不会修改其他对象的状态,也不会和外面的世界交互。

函数式编程风格的代码能给你带来什么好处 ? 首先,简洁。函数式风格的代码 比相应的命令式风格的代码更优雅、更简练,因为把函数当作值可以让你获得更强 大的抽象能力,从而避免重复代码。

假设你有两段类似的代码,实现相似的任务(例如,在集合中寻找一个匹配的 元素)但具体细节略有不同(如何判断元素是匹配的)。可以轻易地将这段逻辑中公 共的部分提取到一个函数中,并将其他不同的部分作为参数传递给它。这些参数本身也是函数,但你可以使用一种简洁的语法来表示这些匿名函数,它被称作 lambda 表达式 :

函数式编程风格的代码带来的第二个好处是多线程安全。多线程程序中最大的错误来源之一就是,在没有采用适当同步机制的情况下,在不同的线程上修改同一份数据。如果你使用的是不可变数据结构和纯函数,就能保证这样不安全的修改根 本不会发生,也就不需要考虑为其设计复杂的同步方案。

最后,函数式编程意味着测试更加容易。没有副作用的函数可以独立地进行测 试,因为不需要写大量的设置代码来构造它们所依赖的整个环境。

一般来说,函数式编程风格可以在任何编程语言中使用(包括 Java),它的很 多主张都被认为是良好的编程风格。然而并不是所有的语言都提供了语法和库支持, 让我们可以毫不费力地使用这种风格。例如,Java 8 之前的 Java 版本都缺少了这种 支持。Kotlin 拥有丰富的特性集从一开始就支持函数式编程风格,包括 :

函数类型,允许函数接受其他函数作为参数,或者返回其他函数。

lambda 表达式,让你用最少的样板代码方便地传递代码块

数据类,提供了创建不可变值对象的简明语法

标准库中包括了丰富的 API 集合,让你用函数式编程风格操作对象和集合

Kotlin 允许你使用函数式编程风格但并没有强制你使用它。当你需要的时候, 可以使用可变数据,也可以编写带副作用的函数,而且不需要跳过任何多余的步骤。 然后,毫无疑问的是,在 Kotlin 中使用基于接口和类层次结构的库就像 Java 一样简 单。当编写 Kotlin 代码的时候,可以结合使用面向对象编程和函数式编程风格,并 使用最合适的工具来对付亟待解决的问题。

免费并开源

Kotlin 语言(包括编译器、库和所有相关工具)是完全开源的,并且可以自由使用。 它采用 Apache 2 许可证 ;其开发过程完全公开在 GitHub (http://github.com/jetbrains/ kotlin) 上,并且欢迎来自社区的贡献。如果你要开发 Kotlin 应用程序,有三种开源 IDE 供你选择 :IntelliJ IDEA Community2 版、Android Studio 以及 Eclipse,它们都完 全支持 Kotlin(当然,IntelliJ IDEA Ultimate 也支持 Kotlin。)

现在你明白了 Kotlin 是什么语言,让我们看看 Kotlin 在具体的实际应用中会给你带来哪些好处。

Kotlin应用

如前所述,Kotlin 使用的两个主要的领域是服务器端和 Android 开发。接下来 我们分别看看这两个领域,以及为什么 Kotlin 非常适合它们。

服务器端的 Kotlin

服务器端编程是一个非常大的概念,它包含了所有下列的应用程序类型甚至更多 :

返回 HTML 页面给浏览器的 Web 应用程序

通过 HTTP 暴露 JSON API 的移动应用后端服务

通过 RPC 协议互相通信的微服务

多年以来,开发者一直在构建这些类型的应用,并且积累了大量的框架和技术 来帮助他们构建这些应用。这些应用通常并不是孤立地开发或者从零开始的,它们 几乎总是对现有的系统进行扩展、改进或者替换,新的代码必须和系统中现有部分 进行集成,而这些部分可能很多年之前就写成了。

这种环境下 Kotlin 的一大优势就是它与现有的 Java 代码无缝的互操作性。无论 是要编写一个全新的组件还是移植一个现有服务的代码,Kotlin 都毫无压力。不管 你需要在 Kotlin 中继承 Java 类,还是以某种方式注解一个类的方法或字段,都不会 遇到任何问题。它带来的优点是系统的代码会更紧凑、更可靠、更易于维护。

与此同时,Kotlin 还引入了许多用于开发这类系统的新技术。例如,对构建器 模式的支持让你可以使用更简洁的语法来创建任何对象图,同时保留了语言中全套 的抽象机制和代码重用工具。

这个特性的一个最简单的用例就是 HTML 生成库,它可以把一个外部模板语言 替换成简洁且完全类型安全的解决方案。这里有一个例子 :

可以轻松地把映射到HTML标签的函数和常规的Kotlin语言结构组合起来。你不再需要使用一门独立的模板语言,也不需要学习新的语法,仅仅使用循环就可以生成HTML页面。

另一个能用上Kotlin干净和简洁的DSL的用例是持久化框架。例如,Exposed 框架(https://github.com/jetbrains/exposed) 就提供了易读的 DSL,可以完全使用 Kotlin 代码来描述 SQL 数据库的结构并执行查询操作,并且有全面的类型检查。下 面这个小例子展示了可行的做法 :

Android 上的 Kotlin

一个典型的移动应用和一个典型的企业应用完全不同。它更小,更少地依赖与 现有的代码集成,通常需要快速交付,同时需要保证在大量的设备上能够可靠地运 行。这类项目 Kotlin 也能胜任。

Kotlin 的语言特性,加上支持 Android 框架的特殊编译器插件,让 Android 的 开发体验变得高效和愉悦。常见的开发任务,比如给控件添加监听器或是把布局元 素绑定到字段,可以用更少的代码完成,有时甚至根本不用写任何代码(编译器会帮你生成)。同样由 Kotlin 团队打造的库 Anko(https://github.com/kotlin/anko) 给许多标准 Android API 添加了 Kotlin 友好的适配器,进一步提升了 Android 的开发体验。

下面是 Anko 的一个简单例子,可以品尝到使用 Kotlin 进行 Android 开发的滋味。只要把这段代码放在一个 Activity 中,一个简单的 Android 应用就做好了!

使用Kotlin带来的另一优势就是更好的应用可靠性。如果你有开发Android应用的经验,你一定对“Unfortunately, Process Has Stopped”对话框深恶痛绝。如果你的应用有未处理的异常,这个对话框就会出现,而这种异常一般是NullPointerException(空指针异常)。Kotlin的类型系统通过精确地跟踪null值,大大减轻了空指针异常问题带来的压力。大部分Java中会导致NullPointerException的代码在Kotlin中无法编译成功,以确保这些错误在应用到达用户手中之前得到修正。

同时,由于 Kotlin 完全兼容 Java 6,使用它并不会带来任何新的编译问题。你 可以享受所有 Kotlin 的酷炫新特性,而你的用户仍然可以在他们的设备上使用你的 应用,即使他们的设备并没有运行最新版本的 Android 系统。

说到性能,Kotlin 也没有带来任何负面影响。Kotlin 编译器生成的代码执行起 来和普通的 Java 代码效率一样。Kotlin 使用的运行时(库)体积相当小,所以编译 出来的应用程序包体积也不会增加多少。当你使用 lambda 的时候,它们会被许多 Kotlin 标准库函数内联。lambda 的内联确保不会创建新对象,因此应用程序也不必 忍受额外的 GC 暂停。

读者评论

相关专题

相关博文

  • 类加载与Java主类加载机制解析

    类加载与Java主类加载机制解析

    管理员账号 2017-08-23

    小编说:类的加载机制与生命周期等概念,在各种书籍与各种网络博客里随处可见,然而对于一个想要真正了解其内部实现的人而言,那些都涉入过浅。本文从JVM源码的角度,还原出Java类加载的真实机制。 本文选自《揭秘Java虚拟机:JVM设计原...

    管理员账号 2017-08-23
    1196 0 0 0
  • 6种常用View 的滑动方法

    6种常用View 的滑动方法

    管理员账号 2017-08-01

    小编说:View 的滑动是Android 实现自定义控件的基础,实现View 滑动有很多种方法,在这里主要讲解6 种滑动方法,分别是layout()、offsetLeftAndRight()与offsetTopAndBottom()、...

    管理员账号 2017-08-01
    1085 0 0 0
  • #小编推书#快速高效地展炫酷动画效果

    管理员账号 2017-02-13

    小编说 目前,APP Store上的应用已经超过150万个,而纵观排名较为靠前的应用,无一例外都有着一个共同的特点,那就是良好的用户体验。动画作为用户体验中最复杂、最绚丽的技术已经备受开发人员和产品设计人员的重视。而如何将炫酷的动画...

    管理员账号 2017-02-13
    400 0 0 0