Kotlin实战(txt+pdf+epub+mobi电子书下载)


发布时间:2020-09-11 21:05:07

点击下载

作者:覃宇等

出版社:电子工业出版社有限公司

格式: AZW3, DOCX, EPUB, MOBI, PDF, TXT

Kotlin实战

Kotlin实战试读:

前言

关于Kotlin想法的构思2010年诞生于JetBrains。当时,JetBrains 已经是许多程序语言开发工具的知名供应商,包括Java、C#、JavaScript、Python、Ruby 和 PHP。Java IDE——IntelliJ IDEA,Groovy和Scala的插件,都是我们的旗舰产品。

为各种程序语言构建开发工具的经验给了我们对语言设计领域全面的理解和独特的观点。而基于 IntelliJ 平台的 IDE,包括IntelliJ IDEA,仍然是用 Java 开发的。我们甚至都有点羡慕在 .NET 团队中的同事,他们使用 C#,一种现代、强大、迅速进化的语言进行开发。但是我们没有看到任何一种可以用来取代 Java 的语言。

对于这样的一门语言我们有哪些要求呢?首要而且最明确的要求就是它必须是静态类型的。我们想象不到其他任何一种——开发一个拥有数百万行代码的代码库许多年后——还不把人逼疯的办法。其次,我们需要与现有的 Java 代码完全兼容。这样的代码库是 JetBrains 的一笔巨大财富,我们承受不起失去它或是因为互操作性的难度而使其贬值的损失。再次,我们不愿意在工具质量方面接受任何的妥协。开发者的生产力是 JetBrains 作为一个公司最重要的价值,而强大的工具是达到这一目的的必要条件。最后,我们需要的是一种易于学习和理解的语言。

当看到一个我们公司未能满足的需要时,我们知道其他公司也处在一个相似的境地,我们希望我们的解决方案能够在 JetBrains 之外找到许多用户。带着这样的初心,我们决定走上一条创建一门新语言:Kotlin 的道路。事实上,这个项目花费了超出我们预期的时间,在 Kotlin 1.0 最终诞生时,距离第一行代码提交到代码库中已经过去了超过五年;但是现在我们可以确信,这门语言找到了它的受众并且这些人都留了下来。

Kotlin 以靠近俄罗斯圣彼得堡的一座岛屿命名,Kotlin 的大部分开发团队就在那里。在使用岛屿命名这件事上,我们遵循了Java和Ceylon确立的先例,但我们决定选用一处靠近我们家乡的地方(在英语中,这个名称通常的发音是“cot-lin”,而不是“coat-lin”或者“caught-lin”)。

在这门语言临近发布之际,我们意识到一本由参与了语言设计决策人员撰写的关于Kotlin的书籍是有价值的,他们可以自信地解释为什么 Kotlin 中的事物是以它们的方式运行的。本书就是这种努力的结果,我们希望它能帮助你学习和理解Kotlin 语言。祝你好运,并愿你一直能愉快地进行开发。致谢

首先,我们想感谢Sergey Dmitriev 和Max Shafirov,感谢他们相信一门新语言的想法并决定投入 JetBrains 的资源。没有他们,这门语言和这本书将不会存在。

我们要特别感谢 Andrey Breslav,他是负责设计这门令人能够愉快地书写(以及编码)的语言的主要人物。Andrey 在领导这支持续增长的 Kotlin 团队之余,也给了我们很多有效的反馈,这让我们非常感激。 另外,你可以放心,本书收到了来自这位首席设计师的认可,他爽快地答应为本书撰写序。

我们非常感谢 Manning 团队,他们引导我们完成这本书的编写过程,并为文字可读性和结构合理性提供了帮助——具体包括,我们的开发编辑 Dan Maharry,尽管我们日程安排非常忙碌,他仍然勇于力争寻找时间跟我们讨论,同样还有Michael Stephens、Helen Stergius、Kevin Sullivan、Tiffany Taylor、Elizabeth Martin和Marija Tudor。来自我们技术审核专员Brent Watson和Igor Wojda的反馈也是非常宝贵的,在开发过程中阅读原稿的审稿人的意见也很重要:Alessandro Campeis、Amit Lamba、Angelo Costa、Boris Vasile、Brendan Grainger、Calvin Fernandes、Christopher Bailey、Christopher Bortz、Conor Redmond、Dylan Scott、Filip Pravica、Jason Lee、Justin Lee、Kevin Orr、Nicolas Frankel、Paweł Gajda、Ronald Tischliar 和Tim Lavers。感谢在 MEAP 计划和书籍论坛中提交反馈的所有人,我们已经根据你们的意见改进了文字。

我们要感谢整个Kotlin团队,在我们撰写这本书的过程中,他们每天都要听“又一个章节完成了”这样的日常报告。我们想感谢帮助我们计划这本书并在草案上给出反馈的同事,尤其是Ilya Ryzhenkov、Hadi Hariri、Michael Glukhikh和 Ilya Gorbunov。我们也想感谢那些不仅给予帮助也同样阅读文本并提供反馈(有时在度假期间的滑雪胜地)的朋友:Lev Serebryakov、Pavel Nikolaev 和 Alisa Afonina。

最后,我们还想感谢我们的家人和使这个世界变得更美好的猫咪们。第1部分Kotlin简介本书第一部分的目标是让你高效地编写使用现有 API 的 Kotlin 代码。第1章将介绍 Kotlin 的主要特征。在第2章~第4章,你将会学习到最基本的 Java 编程概念(语句、函数、类和类型)是如何映射到Kotlin代码中的,以及Kotlin是如何丰富这些概念使得编程变得更加愉悦的。你完全可以依靠对现有的Java知识的理解,借助IDE的编码辅助功能和Java到 Kotlin的转换器来加速掌握这些知识。在第5章中,你会了解lambda是如何帮助你有效地解决编程中最普遍的一些问题的,比如对集合的操作。最后,在第6章,你将会熟悉 Kotlin 的一项重要特性:对null值处理的支持。1 Kotlin:定义和目的

本章内容包括

■ Kotlin的基本示范

■ Kotlin语言的主要特征

■ Android和服务器端开发的可能性

■ Kotlin与其他语言的区别

■ 用Kotlin编写并运行代码

Kotlin到底是什么?它是一种针对Java平台的新编程语言。Kotlin简洁、安全、务实,并且专注于与Java代码的互操作性。它几乎可以用在现在Java使用的任何地方:服务器端开发、Android应用,等等。Kotlin可以很好地和所有现存的Java库和框架一起工作,而且性能水平和Java旗鼓相当。在这一章中,我们将详细地探讨Kotlin的主要特征。1.1 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专家。我们希望不久之后,在你自己的项目中也能看到这样的代码,而不只是在书上。1.2 Kotlin的主要特征

你大概已经知道了Kotlin是一种怎样的语言,让我们更加深入地了解一下它的关键属性。首先,我们来看看你能用Kotlin创造哪些种类的应用程序。1.2.1 目标平台:服务器端、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://[1]github.com/edvin/tornadofx)以及JavaFX一起来构建桌面应用程序。

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

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

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

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

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

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

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

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

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

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

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

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

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

其中最重要的概念是Kotlin对可空类型的支持,通过在编译期检测可能存在的空指针异常,它让你可以写出更可靠的程序。本章后面我们将回顾可空类型,并在第6章中详细讨论。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

如前所述,Kotlin使用的两个主要的领域是服务器端和Android开发。接下来我们分别看看这两个领域,以及为什么Kotlin非常适合它们。1.3.1 服务器端的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数据库的结构并执行查询操作,并且有全面的类型检查。下面这个小例子展示了可行的做法:

本书后面的7.5节和第11章将会详细地剖析这些技术。1.3.2 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相比Kotlin的优势之后,我们再来看看Kotlin的设计哲学——那些把Kotlin和其他面向JVM的现代语言区分开的主要特性。1.4 Kotlin的设计哲学

当谈起Kotlin的时候,我们喜欢说它是一门务实、简洁和安全的语言,专注于互操作性。这里的每个词语究竟是什么含义?我们逐个来看看。1.4.1 务实

务实对我们来说意味着一件简单的事情:Kotlin就是一门设计出来解决现实世界问题的实用语言。它的设计基于多年创建大型系统的工业经验,它的特性也是为解决许多软件开发者遇到的场景而选择的。此外,来自JetBrains内部和社区的开发者已经使用Kotlin的早期版本很多年,他们的反馈也被融合进了这门语言公开发布的版本中。所以我们才能自信地说,Kotlin能够帮助解决实际项目的问题。

Kotlin也不是一门研究性的语言。我们没有试图提升编程语言设计领域目前的技术水平,也没有尝试探索计算机科学的创新理念。反而,我们会尽可能地依赖已经出现在其他编程语言中并被证明是成功的那些特性和解决方案。这降低了语言的复杂性,也让它更容易学习,因为你可以仰仗那些熟悉的概念。

此外,Kotlin也没有强制使用某种特定的编程风格和范式。当你开始学习这门语言的时候,可以使用熟悉的来自Java经验的风格。然后,你会渐渐地发现更多强大的Kotlin特性,并学习把它们应用到你的代码中,让代码更简洁、更符合语言习惯。

Kotlin的实用主义的另一个重要体现是对于工具的专注。对开发者的生产力而言,一个智能的开发环境和一门设计良好的语言同样重要。因此,事后再来考虑对IDE进行支持就是马后炮。而Kotlin的情况是,IntelliJ IDEA的插件是和编译器同步开发的,并且在设计语言特性时始终牢记着对工具的支持。

IDE支持对帮助你探索Kotlin的特性也发挥着重要作用。许多情况下,工具会发现那些可以用更简洁的结构来替换的通用代码模式,并给你提供修正这些代码的选择。通过研究自动修正所使用的语言特性,你就能学习如何在自己的代码中应用这些特性。1.4.2 简洁

和编写新代码相比,开发人员会耗费更多的时间来阅读现有代码,这已经是常识。想象一下你所在的团队正在开发一个大项目,而你的工作是添加一个新特性或者修改bug。第一步会干什么?首先要找到需要改变的那段代码,然后才能实现你的修改。要阅读很多代码才能知道你要做什么。这些代码可能最近刚完成,由你的同事或者是那些已经离开的同事编写,或者是你自己很久之前写好的。只有搞懂了周围的代码你才能做出正确的改动。

代码越简单越简洁,你就能越快地了解发生了什么。当然,良好的设计和达意的命名在这里起着重要的作用。但语言的选择及其简洁性也很重要。如果语言的语法清晰地表达了被阅读的代码的意图,没有因为达成意图所需的样板代码而晦涩难懂,那么它就是简洁的。

在Kotlin中,我们努力地保证你写的代码都具有实际的意义,而不是仅仅为了满足代码结构的需要。许多标准的Java样板代码,例如getter、setter以及将构造方法的参数赋值给字段的逻辑,在Kotlin中都是隐式的,并不会使你的源代码变得混乱。

另外一个导致代码变得不必要的冗长的原因是编写显式的代码来完成常见的任务,比如定位集合中的元素。和许多其他现代语言一样,Kotlin有丰富的标准库,让你用库方法调用来代替这些冗长重复的代码段。Kotlin对lambda的支持,让小代码块可以轻松地传递给库函数。这让你可以把公共的那部分代码全部封装在库中,而在用户代码中仅保留特定的针对任务的那部分。

与此同时,Kotlin并没有尝试把源代码压缩到最小可能的长度。例如,即使Kotlin支持运算符重载,用户也不能定义自己的运算符。因此,库开发者不能用神秘的标点符号序列来代替方法名字。单词比标点符号显然更易读,也更容易找到相关的文档。

越简洁的代码写起来花的时间越短,更重要的是,读起来耗费的时间也更短。这会提高你的生产力并让你更快地达成目标。1.4.3 安全

通常,我们说一门编程语言是安全的,我们的意思是它的设计可以防止程序出现某些类型的错误。当然,这并不意味着绝对的高质量,没有任何语言可以阻止所有可能出现的错误。此外,预防错误是需要成本的。需要给编译器提供程序有关预期操作更多的信息,这样编译器才能验证这些信息是否和程序的功能匹配。因此,你要在得到的安全级别和因为增加更多细节注解而造成的生产力损失之间权衡利弊。

使用Kotlin,我们试图实现比Java更高的安全级别,同时保持更低的总体成本。在JVM上运行已经提供了许多的安全保证:例如,内存安全,防止了缓冲区溢出以及其他错误的动态内存分配造成的问题。作为面向JVM的静态类型语言,Kotlin还保证了应用程序的类型安全。这比使用Java的成本要更低:不需要指定所有的类型声明,因为许多情况下编译器会自动地推断出类型。

Kotlin所做的不止这些,这意味着更多的原本在运行时失败的错误在编译期的检查中就被阻止了。最重要的一点是,Kotlin努力地从你的程序中消除NullPointerException。Kotlin的类型系统跟踪那些可以或不可以为null的值,并且禁止那些运行时可能导致NullPointerException的操作。这所带来的额外的成本是极小的:把类型标记为可空的只要一个字符,就是类型尾部的一个问号:

除此之外,Kotlin提供了许多便利的方法来处理可空数据。这非常有助于消灭应用程序的崩溃。

Kotlin有助于避免的另一种异常类型就是ClassCastException。当你把一个对象转换成一种类型,而没有事先检查它是否是正确的类型时,就会发生这个异常。在Java中,开发者常常省略了这类检查,因为必须反复地在检查和其后的转换中写明类型名称。另一方面,Kotlin中的检查和转换被组合成了一次操作:一旦检查过类型,不需要额外的转换就能直接引用属于这个类型的成员。这样,开发者就没有借口跳过检查,也不会给错误留下可乘之机。下面展示了它是如何工作的:1.4.4 互操作性

关于互操作性,你的第一个问题可能是:“我是不是可以继续使用现有的库?”Kotlin给出的回答是:“当然可以。”无论需要使用哪种库提供的API,都可以在Kotlin中使用它们。可以调用Java的方法,继承Java的类和实现Java的接口,在Kotlin类上应用Java的注解,等等。

与其他一些JVM语言不同,Kotlin在互操作性上更上一层楼,让Java代码也可以毫不费力地调用Kotlin的代码。无须取巧:Kotlin的类和方法可以像常规的Java类和方法一样被调用。这带来了无限的灵活性,在项目的任何地方都可以混合使用Java和Kotlin。当你刚开始在自己的Java项目中引入Kotlin时,可以在代码库中的任意一个类上运行Java到Kotlin的转换器,剩下的代码不需要任何修改就可以继续编译和工作。不管你所转换的类是什么角色,这都是可行的。

另一个Kotlin专注于互操作性的领域是在最大程度上使用现有的Java库。例如, Kotlin没有自己的集合库,它完全依赖Java标准库中的类,使用额外的函数来扩展它们,让它们在Kotlin中用起来更方便(我们会在3.3节中了解这种机制更多的细节)。这意味着在Kotlin中调用Java API时,永远不需要包装或者转换这些Java对象,反之亦然。所有这些Kotlin提供的丰富的API在运行时没有任何的额外开销。

Kotlin工具也对跨语言项目提供了全面支持。它可以编译任意混合的Java和Kotlin源码,不管它们之间是怎样互相依赖的。IDE的特性也能跨语言工作,允许:

● 自由地在Java和Kotlin源码文件之间切换

● 调试混合语言的项目,可以在不同语言编写的代码之中单步调试

● 重构Java方法的时候,Kotlin代码中的对它们的调用也会得到正确的更新,反之亦然

希望我们已经说服你尝试一下Kotlin。现在,你要如何开始使用它?在接下来的一节中,我们将从命令行和其他不同工具的使用两方面讨论编译和运行Kotlin代码的过程。1.5 使用Kotlin工具

和Java一样,Kotlin也是编译型语言。这意味着你必须先编译,然后才能执行Kotlin代码。让我们来讨论一下编译过程,然后看看帮你完成这个过程需要的不同工具。如果你需要关于如何搭建开发环境的信息,请参考Kotlin官方网站的“Tutorials”(教程)一节(https://kotlinlang.org/docs/tutorials)。1.5.1 编译Kotlin代码

Kotlin的源代码存放在后缀名为.kt的文件中。Kotlin编译器会分析源代码并生成.class文件,这和Java编译器做的没什么不同。然后按照你正在处理的应用程序类型的标准过程打包和执行生成的.class文件。最简单的情况下,只需要使用kotlinc命令就可以从命令行编译代码,然后就可以用java命令执行你的代码:

图1.1展示了Kotlin构建过程的简单描述。图1.1 Kotlin构建过程

用Kotlin编译器编译的代码依赖Kotlin运行时库。它包括了Kotlin自己的标准库类的定义,以及Kotlin对标准Java API的扩展。运行时库需要和你的应用程序一起分发。

在大多数实际工作的例子中,你会使用像Maven、Gradle或者Ant这样的构建系统来编译你的代码。Kotlin和所有这些构建系统都兼容,我们会在附录A中讨论相关细节。所有这些构建系统也支持在同一个代码库中既有Kotlin也有Java的混合语言项目。此外,Maven和Gradle还会帮你把Kotlin运行时库作为依赖加入到你的应用程序中。1.5.2 IntelliJ IDEA和Android Studio插件

IntelliJ IDEA的Kotlin插件是和语言同步开发的,它是Kotlin可用的功能最全面的开发环境。它成熟且稳定,提供了Kotlin开发所需的全套工具。

IntelliJ IDEA 15及其后续版本不需要额外的设置,Kotlin插件就可以开箱即用。可以选择免费开源的IntelliJ IDEA Community版,也可以选择IntelliJ IDEA Ultimate。在“New Project”(新建项目)对话框中选择“Kotlin”,然后就可以开始工作了。

如果你用的是Android Studio,可以从“plug-in manager”(插件管理器)中安装Kotlin插件。打开“Settings”(设置)对话框,选择“Plugins”(插件),单击“Install JetBrains Plugin”(安装JetBrains插件)按钮,然后从列表中选择“Kotlin”。1.5.3 交互式shell

如果你想快速地尝试小段的Kotlin代码,可以使用交互式shell(也[3]叫REPL)。在REPL中,可以逐行地输入Kotlin代码并立即看到其执行结果,可以使用不带任何参数的kotlinc命令启动REPL,也可以从IntelliJ IDEA的“Kotlin”菜单中选择启动REPL。1.5.4 Eclipse插件

如果你是Eclipse用户,同样可以选择在你的IDE中使用Kotlin。Kotlin的Eclipse插件提供了必要的IDE功能,如导航和代码补全。该插件可以在Eclipse Marketplace中找到。要安装它,请选择“Help > Eclipse Marketplace”菜单项,然后在列表中搜索“Kotlin”。1.5.5 在线playground

尝试Kotlin的最简单的方式,是不需要任何安装和配置。可以在http://try.kotl.in找到在线的playground,可以在上面编写、编译及运行Kotlin的小程序。Playground上还展示了Kotlin特性的代码示例,其中包括了本书中的所有例子,还有一系列交互式学习Kotlin的练习。1.5.6 Java到Kotlin的转换器

要熟练掌握一门新语言总是要费点力气的。幸运的是,我们开辟了一条很棒的小捷径,让你可以借助现有的Java知识来加快学习和运用Kotlin的速度。这个工具就是Java到Kotlin的自动转换器。

当你开始学习Kotlin的时候,如果你还没有记住准确的语法,转换器能帮你表达一些内容。可以先用Java写出相应的代码片段,然后把它粘贴到Kotlin文件中,转换器会自动地将代码转换成Kotlin。转换的结果不一定总是符合语言习惯,但是它一定是可以工作的代码,这样就可以让你的任务更进一步了。

在现有的Java项目中引入Kotlin时,转换器也很好用。当你写一个新类时,可以从一开始就用Kotlin。但是如果你要在一个现有的类上做重大的更改时,可能也想在这个过程中使用Kotlin,这时转换器就派上用场了。首先把这个类转换成Kotlin,然后就可以利用现代编程语言的所有优势来添加更改了。

在IntelliJ IDEA中使用转换器再简单不过了。要么复制一段Java代码粘贴到Kotlin文件中,要么触发“Convert Java File to Kotlin File”(转换Java文件到Kotlin文件)动作来转换整个文件。也可以在Eclipse中或者线上使用转换器。1.6 小结

● Kotlin是静态类型语言并支持类型推导,允许维护正确性与性能的同时保持源代码的简洁。

● Kotlin支持面向对象和函数式两种编程风格,通过头等函数使更高级别的抽象成为可能,通过支持不可变值简化了测试和多线程开发。

● 在服务器端应用程序中它工作得很好,全面支持所有现存的Java框架,为常见的任务提供了新工具,如生成HTML和持久化。

● 在Android上它也可以工作,这得益于紧凑的运行时、对Android API特殊的编译器支持以及丰富的库,为常见Android开发任务提供了Kotlin友好的函数。

● 它是免费和开源的,全面支持主流的IDE和构建系统。

● Kotlin是务实的、安全的、简洁的,与Java可互操作,意味着它专注于使用已经证明过的解决方案处理常见任务,防止常见的像NullPointerException这样的错误,支持紧凑和易读的代码,以及提供与Java无限制的集成。2 Kotlin基础

本章内容包括

■ 声明函数、变量、类、枚举以及属性

■ Kotlin 中的控制结构

■ 智能转换

■ 抛出和处理异常

在这一章我们将学习怎样用Kotlin声明任何程序都存在的基本要素:变量、函数和类,顺便熟悉Kotlin的属性概念。

我们会学习怎样在Kotlin中使用不同的控制结构。这些结构大部分都和那些你熟知的Java结构相似,但在一些重要的方面增强了。

我们会介绍智能转换的概念,它把类型检查和类型转换合并成了一次操作。最后,我们会谈到异常处理。在学习完本章的内容后,你就能掌握这门语言的基础知识,并利用这些知识编写出可以工作的Kotlin代码,哪怕有些写法还不是最符合语言习惯的。2.1 基本要素:函数和变量

这一节会向你介绍组成每个Kotlin程序的基本要素:函数和变量。你将看到Kotlin如何让你省略许多类型的声明,以及它如何鼓励你使用不可变的数据而不是可变的数据。2.1.1 Hello,world!

让我们从最经典的例子开始:一个打印“Hello, world!”的程序。在Kotlin中,这只需要一个函数就可以实现:代码清单2.1 Kotlin的“Hello, world!”

你能从这样简单的一小段代码中观察到哪些特性和语法?看看下面这个列表:

● 关键字fun用来声明一个函数。没错,Kotlin编程有很多乐趣(fun)!

● 参数的类型写在它的名称后面。稍后你会看到,变量的声明也是这样。

● 函数可以定义在文件的最外层,不需要把它放在类中。

● 数组就是类。和Java不同,Kotlin没有声明数组类型的特殊语法。

● 使用println代替了System.out.println。Kotlin标准库给Java标准库函数提供了许多语法更简洁的包装,而println就是其中一个。

● 和许多其他现代语言一样,可以省略每行代码结尾的分号。

目前为止感觉还不错!我们稍后会更详细地讨论其中一些话题。现在,我们先来研究一下函数声明语法。2.1.2 函数

你已经看到了怎样声明一个没有返回任何东西的函数。但是如果函数有一个有意义的结果,返回类型应该放在哪里呢?你可能会猜到它应该位于参数列表之后的某处:

函数的声明以关键字fun开始,函数名称紧随其后:这个例子中函数名称是max,接下来是括号括起来的参数列表。参数列表的后面跟着返回类型,它们之间用一个冒号隔开。

图2.1向你展示了一个函数的基本结构。注意在Kotlin中,if是有结果值的表达式。它和Java中的三元运算符相似:(a>b)?a: b。图2.1 Kotlin函数声明

语句和表达式

在Kotlin中,if是表达式,而不是语句。语句和表达式的区别在于,表达式有值,并且能作为另一个表达式的一部分使用;而语句总是包围着它的代码块中的顶层元素,并且没有自己的值。在Java中,所有的控制结构都是语句。而在Kotlin中,除了循环(for、do和do/while)以外大多数控制结构都是表达式。这种结合控制结构和其他表达式的能力让你可以简明扼要地表示许多常见的模式,稍后你会在本书中看到这些内容。

另一方面,Java中的赋值操作是表达式,在Kotlin中反而变成了语句。这有助于避免比较和赋值之间的混淆,而这种混淆是常见的错误来源。

表达式函数体

可以让前面的函数变得更简单。因为它的函数体是由单个表达式构成的,可以用这个表达式作为完整的函数体,并去掉花括号和return语句:

如果函数体写在花括号中,我们说这个函数有代码块体。如果它直接返回了一个表达式,它就有表达式体。

INTELLIJ IDEA 小贴士 IntelliJ IDEA 提供了在两种函数风格之间转换的intention actions(意向动作):“Convert to expression body”(转换成表达式函数体)和“Convert to block body”(转换成代码块函数体)。

在Kotlin代码中会常常看到表达式体的函数。这种风格不光用在一些简单的单行函数中,也会用在对更复杂的单个表达式求值的函数中,比如if、when以及try。你会在本章后面介绍when结构的内容中看到这样的函数。

还可以进一步简化max函数,省掉返回类型:

为什么有些函数可以不声明返回类型?作为一门静态类型语言,Kotlin 不是要求每个表达式都应该在编译期具有类型吗?事实上,每个变量和表达式都有类型,每个函数都有返回类型。但是对表达式体函数来说,编译器会分析作为函数体的表达式,并把它的类型作为函数的返回类型,即使没有显式地写出来。这种分析通常被称作类型推导。

注意,只有表达式体函数的返回类型可以省略。对于有返回值的代码块体函数,必须显式地写出返回类型和return语句。这是刻意的选择。真实项目中的函数一般很长且可以包含多条return语句,显式地写出返回类型和return语句能帮助你快速地理解函数能返回的是什么。接下来我们看看声明变量的语法。2.1.3 变量

在Java中声明变量的时候会以类型开始。在Kotlin中这样是行不通的,因为许多变量声明的类型都可以省略。所以在Kotlin中以关键字开始,然后是变量名称,最后可以加上类型(不加也可以):

这个例子省略了类型声明,但是如果需要也可以显式地指定变量的类型:

和表达式体函数一样,如果你不指定变量的类型,编译器会分析初始化器表达式的值,并把它的类型作为变量的类型。在前面这个例子中,变量的初始化器42的类型的是Int,那么变量就是这个类型。

如果你使用浮点数常量,那么变量就是Double类型:

第6.2节会更深入地介绍算术类型。

如果变量没有初始化器,需要显式地指定它的类型:

如果不能提供可以赋给这个变量的值的信息,编译器就无法推断出它的类型。

可变变量和不可变量

声明变量的关键字有两个:

● val(来自value)——不可变引用。使用val声明的变量不能在初始化之后再次赋值。它对应的是Java的final变量。

● var(来自variable)——可变引用。这种变量的值可以被改变。这种声明对应的是普通(非final)的Java变量。

默认情况下,应该尽可能地使用val关键字来声明所有的Kotlin变量,仅在必要的时候换成var。使用不可变引用、不可变对象及无副作用的函数让你的代码更接近函数式编程风格。第1章中简要地介绍了这种风格的优点,在第5章中会再次回到这个话题。

在定义了val变量的代码块执行期间,val变量只能进行唯一一次初始化。但是,如果编译器能确保只有唯一一条初始化语句会被执行,可以根据条件使用不同的值来初始化它:

注意,尽管val引用自身是不可变的,但是它指向的对象可能是可变的。例如,下面这段代码是完全有效的:

第6章中,我们会更详细地讨论可变对象和不可变对象。

即使var关键字允许变量改变自己的值,但它的类型却是改变不了的。例如,下面这段代码是不会编译的:

使用字符串字面值会发生错误,因为它的类型(String)不是期望的类型(Int)。编译器只会根据初始化器来推断变量的类型,在决定类型的时候不会考虑后续的赋值操作。

如果需要在变量中存储不匹配类型的值,必须手动把值转换或强制转换到正确的类型。我们会在6.2.3节中讨论基本数据类型之间的转换。

现在你学会了怎样定义变量,是时候看看更多引用变量值的新技巧了。2.1.4 更简单的字符串格式化:字符串模板

让我们回到本章开始的“Hello World”的例子。下面展示了如何完成这个经典练习的下一步:用Kotlin的方式来和人打招呼:代码清单2.2 使用字符串模板

试读结束[说明:试读内容隐藏了图片]

下载完整电子书


相关推荐

最新文章


© 2020 txtepub下载