为啥 Kotlin 是我下一个要掌握的语言

jopen 8年前

Kotlin 是 JetBrains 的一门新的编程语言,这个公司开发了世界上最好用的 IDE。经过一段时间的研究,我决定将其作为今后5到10年的时间里用到的一门编程语言。

我很喜欢 Kotlin,它肯定会成为一个成功的项目。有人看到我在我的开源项目里用了这门语言,就让我说点什么,那么在这篇文章里我就来说一说为什么我觉得 Kotlin 好了。接下来我还会说一下,如果你现在就开始用这门语言,会遇到的问题。最后我会告诉你 Kotlin需要用到 JVM,这个你需要考虑一下(因为你也许正在用 Go 或者 Node),但是我认为这不是问题。

请注意 Kotlin 目前还是 beta 版:1.0正式版有望在2015年底发布,会提供稳定的语言特性和标准库

Kotlin好在哪里

本文一开始似乎有点奇怪:通常鼓吹某个编程语言的文章一上来都会列出新语言都有哪些酷的特性。不过本文不是这样,哪些我们稍后一些再聊。

我们先了解一下其他方面,因为针对开发人员评估编程语言,一个2013年的研究表名,编程语言的特性相对于语言的生态来说,重要程度相对要低一些,这也跟我的经验相符。那么,下面就是我们需要先介绍的:

Kotlin 会编译成 JVM 字节码或者 JavaScript。它不需要新写一个编程语言内核。Java 开发者肯定会很感兴趣这门语言,不过对于其他所有使用带有垃圾收集机制的语言的开发者来说,同样值得关注,这些语言包括 Scala, Go, Python, Ruby 和 JavaScript。

Kotlin 源自产业界, 而非学院。它解决了当前程序设计所面临的实际问题。例如,类型系统可以避免空指针异常的问题。

使用 Kotlin 不需要费用! 它是开源的, 但这不是我要说的,我要说的是它有一个高质量的,Java 到Kotlin 转换工具,非常关注 Java 二进制的兼容性。你可以将一个 Java 工程全部转换,一次只能转换一个文件。甚至上百万行的复杂程序。这就是我为什么使用 Kotlin 的原因,我期待所有的开发者都使用它。

上面已经显示,Kotlin 程序可以使用已经存在的 Java 框架和类库,甚至依籁注解处理的高级框架。互操作是无缝的,而且不需要包装器和适配层。它可以集成Maven,Gradle或者其他的编译系统。

它很容易上手,简单地阅读一下参考手册几个小时就可以学. 语法精益而直观。Kotlin 有点像 Scala, 但它更简单。语言平衡了简洁和可读性。

它没有强制的编程哲学,像过度函数编程和面向对象风格。

它没有运行时开销, 标准库小而紧凑,它主要包括 Java 标准库的扩展。大量使用内联编译时间的功能性结构类似 map/filter/reduce 管道。

与 Anko 和 Kovenant 这样的框架结合,轻量的资源意味着 Kotlin 开始在 Android 开发者中流行如果你在做 Android 开发,你很快就会获得好的工作单位。你可以阅读 a report written by a developer at Square,分享了他们使用 Kotlin 和 Android 的经验,Kotlin 代码就像 Java 一样。完全支持调试,单元测试,分析等等。

除 Android 之外, 我认为 Kotlin 特别适合于处理商业 Java 业务。如果你在一个很大的公司整天面对着一个庞大的 Java 代码库,那么你应该赶快着手研究 Kotlin 了:

  • Kotlin 有着知名公司提供的强有力的商业支持。JetBrains 承诺:有一个高效出色的大型团队正在致力于 Kotlin 的开发工作,而且对 Kotlin 运用稳定的商业模式,甚至正在将自己的部分旗舰产品转换成用于使用 Kotlin。于是 Kotlin 不太可能会在短期内被抛弃。

  • 采用 Kotlin 是低风险的:可以在你代码库的一小部分里,通过一两个热衷于此的团队成员在不影响项目其他代码的前提下进行试用。Kotlin 的类能够导入一个 Java 的 API,使得这看起来就像正常的 Java 代码

  • 由于 Kotlin 专注于语法的可读性,从而使得代码的审查易于进行:即便不熟悉 Kotlin 语言的团队成员也同样可以完成.

  • Kotlin以Java 6 为目标,所以即使在部署新版本 JVM 遇到困难的情况,你也仍然能够使用Kotlin。

今年的早些时候我曾向一家大型保险公司,瑞士再保公司(Swiss Re)的一个以 Java 和 .NET 作为架构的团队展示过 Kotlin. 我以这样的方式开始,用 Java 定义了一个类,这个类带有一些字段,和 toString, equals, hassCode 诸如此类的方法等等。这大约用了 50 行代码。当我将其转化为 Kotlin 的时候(基本上是自动完成的),这个类缩小到了只剩一行代码。然后我又演示了其他可以节省敲代码时间的特性。看到这些他们都很激动,并将 Kotlin 视为他们项目的潜在竞争者。

我想 Kotlin 为商用 Java 开发提供了一个恰当的时机,所以尽管 Kotlin 可以免费使用,不过随着商业版本 IDE 销售额的增加,我预计 JetBrains 定会大赚一笔. 而这也将刺激他们依照广大客户的意愿来不断提升自身的产品.

与此相比,那些从与现有IDE不相关的产品中得到资助的其他语言开发者们,他们则很少会因为用户的需求与自身产品先入为主的理念不一致,就做出相应的调整。


功能特性

Kotlin 因其对生态系统上的关注而从海量新兴编程语言中脱引而出: JetBrains 了解到生产力的来源不只是在于更方便的语法。

尽管如此,Kotlin 还是有许多有用的功能特性,它们让编写代码的人乐在其中:

  • 我们已经提起过 空指针安全 (这是可选的一项功能),它会让编译器系统性的将潜在的空指针标识为无效的。不想某些语言那样,这并不会涉及到一个可选类型且因此是零开销的 。其它的语言特性确保了它不会是不方便的。

  • 精益的语法: 类型推断在任何地方都能起作用,单行方法只用一行就行了,简单的结构体或者JavaBean也可以用一行就能被声明出来。 Real 属性 会在幕后为 Java 互操作生成 getFoo/setFoo 方法。函数可以存在于类的外部。

  • 异常是未经检查的。

  • 向一个类添加 data 注解会触发样板程序的自动生成,像是 equals, hashCode, toString, copy 方法还有对可变扩展的支持。无需构建器你就很方便的拥有了不可变的类。

  • 而如果你确实需要构建复杂的结构,有一种灵巧的语言特性的组合能使得 构建器 条理清晰且类型安全(读是可自动完成的)。如果你是使用的 Google Protocol Buffers 来存储结构性的数据,那也会更加的容器

  • 对函数式编程的支持 使用了 零开销的 lambda 以及在 Java 集合上做映射和折叠的能力。Kotlin 的类型系统能在集合上做可变和不可变视图的区分。

  • 扩展函数 让你可以给类添加方法,而无需修改他们的源代码。这在初次看起来像是一个用来避免 FooUtils 风格的类的语法糖。到后来你会发现这样做让你可以很容易的通过自动补全功能来发现新的方法,使你可以构建出强大的语言扩展并让你可以将现有的 Java API 同 Kotlin 的特性集成。这些特性有 …

  • 操作符重载而这个确实不错:这里没有 Scala / Perl 风格的行捣乱了。操作符映射到特定的方法名称,如此就能重载现有操作符的行为了(包括函数的调用), 但是你不能定义一个完全是新的操作符。这样就达到了能力和可读性之间的一个平衡。

  • Kotlin 并没有宏或者其它方式来对语言进行重新定义,但是有一些小心设计出来的特性,使得那些库表现得更像语言扩展,而不是对象的集合。

  • 你会喜欢使用 fiber, actor, 和 Go风格的 channel 吗? 一个叫做 Quasar 的库为你涵盖到了这些

  • 使用 Markdown 而不是 HTML 来制作你的 API 文档。这使得编写 JavaDoc 令人高兴了许多。

  • 更好的 generics。如果你在放入一个类型变量时,超类和扩展究竟有什么意义从未得到完全认真的处理, 别担心:这不是你的问题。Java 的 generics 确实有点令人困惑。Kotlin 解决了这个问题。

  • 派发 (转发方法) 是自动的。

  • == 操作符真正做了你实际期望的事情。

  • 你喜欢快速和方便的异步编程? 你当然会喜欢的。

  • 字符串插值“works like ${this.example}!”

  • 函数参数可以被命名、可选而且类型可变。

  • 许多许多其它的调整和改进。如果 Java 的有些东西让你不爽的话,我感觉其中一半的不爽在  Kotlin 中都不会有。

现在就来试一下!

跟很多现代编程语言一样,Kotlin 可以通过浏览器来进行实验性的使用。不过跟其他语言不一样的是,Kotlin 的实验网站展现给你的是一个完全成熟的 IDE,包括响应很快的自动完成,实时的背景编译,甚至还有在线的静态分析!

来试试吧

继续尝试一下。然后回来我们继续。

有啥问题不?

生活中没有十全十美,Kotlin 也如此。这里是我试用这门编程语言时遇到的一些问题。

最大的问题是不成熟。Kotlin 是一个未到 1.0 版本的语言。 这意味着:

  • 语言本身,ABI 和 标准库会在每个发行版中发生变化。好消息是,这些变化往往都比较小,而且 Intellij 可以经常为你升级你的代码。所以这没有听起来那么痛苦。

  • Java-to-Kotlin 转换器 (J2K) 还未开发完成。它有时会胡乱的格式化并且会默默的删除 Java 8 lambda 表达式(2015 年 10 月修改:用于 M13 版的转换器目前已经可以正确的处理 Java 8 的特性)。而且它产生的代码也不总是最佳的编写方式。但是 JetBrains 公司正在为这个工具投入显著的精力,而且这已经是我用过的同类产品之中最好的了。所以我并不太担心这一点:它将很快的越来越完善。

  • 遇到编译器 bug。我的程序并不大,但我经常遇到应该编译的代码没有被编译,或者(更糟糕的情况)代码被编译成了错误的东西。诊断这些问题并不是太困难,但这会给我们带来不好的体验。

  • 遇到内部 IDE 错误。 当发生这种情况时你会看到一个提示气泡以及一个汇报给 JetBrains 公司的选项。IDE 不会关闭,大多数错误似乎没有太大的问题。但无论如何,这是很烦人的。

  • 文档有时会参考未实现的特性(修改:在 M14 版本中我相信这已经不再是一个问题了)。

现在 JetBrains 公司正在专注于 1.0 版本的完善而不是添加新特性,我希望这些问题都已经得到解决。

我遇到的第二大的问题,就是有时候其与 Java 的交互有一些局限。

一个典型的 bug 就是 Java 的类型系统无法保证你不改变 map 中 key 的类型。按照常理来说,如果你这样做将会导致编译错误,比如说,使用错误类型的 key 来删除元素。但是当 JDK 集合使用了泛型,其中有些重要的方法的参数是 Object 的话,编译器就不会报错。在 Intellij 中编写 Java 代码时这种情况可以被标记成黄色的静态分析警告,但到目前为止 Kotlin 编辑器还没有这种功能(某些时候)。因为 Kotlin 没有定义任何自己的集合类库,这将导致一些类型安全性方面的一些问题,我已经遇到过好几次了。

另一个例子是,当调用或使用 Java 代码时,Kotlin 的 null 的安全特性是被禁用的(可以使用注解来弥补)。因为做为 Kotlin 初学者你可能会写很多调用 Java 类库的代码,但是这个功能没有你希望的那么有用。这只能等到 Kotlin 占有量增长来改善了。JetBrains 公司已经在尝试解决与 Java 交互时 null 的安全特性的问题了:他们的想法是好的,但是有时却未能发现问题。他们想要这么做来修复 null 的安全特性与 Java 交互的问题。(修改:在 M13 版中他们使用 Java @NotNull 注解来解决

另一方面,这也能让你更流畅的使用 Java API,我认为这种折衷是值得的。但是需要多加注意。

其他需要考虑的问题:

  • 社区比较小。虽然出色的与 Java 交互性意味着你并不真的需要 Kotlin 库,不过有总比没有强,然而目前并不多。

  •  如果你喜欢通过看书来学习,你将不得不等到今年晚些时候, Manning 将会出版一本。在此之前并没有任何网站或其他东西。

  • 函数式编程(FP)的死忠可能会觉得类型系统缺乏类似 Scala 或 Haskell 中的一些高级的功能。如果你是比较在乎类型系统的人,Kotlin 可能并不适合你。

  • 虽然它可以向下编译成 JavaScript,但这种模式似乎与 JVM 后台相比不太好用,你可能会遇到更多的问题,需要说明的是我也没有使用它的经验,这只是在逛论坛时我留下的印象(修改:为了更快的推出 Kotlin 1.0 版,JS 后台已经是非优先的了,当在 JVM 上稳定之后 JetBrains 才会继续做这项工作)。

  • 没有标准风格的指南,而且有时 Kotlin 会提供好几种语法让你选择。不同程序员写的 Kotlin 代码可能看起来是不一样的。这是对于 Go 语言的硬性强制风格来说的。
    修改:在 M14 版本中去掉了一些语法的灵活性,所以操作者必须明确的标示。

  • Kotlin 的编译速度比 Java 稍微慢一点,而且 Intellij 编辑器更慢。但并不是很严重,而且二者都比 Scala 要快。

  • 有一个 Kotlin 的 Eclipse 插件,但自然它的完善度要比 Intellij 支持的少得多。Kotlin 在你的团队规定使用 Intellij 开发时才能工作在最佳状态。

  • Kotlin 比 Java 更挑剔。它不会自动将整型转换成长整型,你必须明确的显式转换。这是因为该语言更看重正确性,而且尝试修复在“Java 解惑”一书中发现的一些著名的问题。JetBrains 公司声称他们修正了其中的一半。

  • 因为 Kotlin 是基于 Java 6 的,它只包含该运行时具有的功能。虽然他可以在很多领域中赶上或超过 C#,但它缺乏还不是 Java 平台的一部分的类似值类型的特性。

为什么你真的需要对 JVM 做一些考虑

最近一段时间我遇到了很多使用动态脚本语言(如JavaScript,Go)的创业公司。

我在比特币工作的时候,使用动态语言是非常痛苦的事情。在这些工具里没有安全性的类型导致了巨大的货币损失。Go 出错少点,但是仍然在基础的东西上体验很差,比如说缺少好的调试工具,快速 GC,稳健的管理器还有可靠的分析工具。

过去15年或更长时间,Java 变得越爱越长,并且被过分使用--在很大程度上源于它的声誉。企业级 Java 的类的名字类似于 PathVariableMapMethodArgumentResolver 那么长。很长一段时间,我不考虑 JVM,我确信这种环境不是给我设计的。

最终我因为要搞 Android 而不得不转向 Java。结果发现已经变了样。虽然 XML 比起我们根据潮流所做的预期来,仍旧更加频繁的被派上用场,而基础设施的能力已经非常令人印象深刻了。IntelliJ 比起 Eclipse 来要快很多也更加的直观。Maven,尽管一开始的时候势不可挡,结果却是大量在其它构建/依赖管理系统中有的功能特性才是我想要的。较新的像 Ninja 和 Play 这些 web 框架从诸如 Ruby on Rails 这样的项目那里学到了敏捷的方法。还有大量的库。硬件已经变得更好了,JVM 也变得更有效率。诸如此类,不一而足。

一个比较大的,还并没有真的发生改变的东西就是语言本身。Java 的代码写起来仍然是冗长而令人痛苦和乏味的。

如今有了 Kotlin,传统中同 Java 生态系统有关的最后一个痛点也成了过去式。你可以编写更具表达能力,而且甚至比一种脚本语言更简洁的代码,然而 bug 更少,性能也更好。你可用上所有这些很棒的工具:只要尝试一下捆绑的 VisualVM 程序,来体味一下在这个生态系统中那些可以免费试用的东西,或者如果你愿意花些钱,就可以上 Chronon 时间旅行调试器 网站看看你可以得到些什么。

如果你喜欢 JavaScript,可以尝试 Kotlin 的后端JS。或者在 Nashorn JS 引擎里运行你现有的代码。

最后,如果你喜欢 GO 语言是因为它会生成独立的程序,看看 javapackager 的工具。Kotlin 在本地为每个平台创建了捆绑包,这意味着在 linux 上不需要 JRE 的依赖就可以独立自主的获取 DEBs(linux 的安装包)或者压缩包。当然,从部署的角度来看,它拆开之后不是单个文件,而是不难运作的单个目录。

简而言之:如果你之前因为 JVM 的生态不流行而忽略了它,你可以再看看 Kotlin 或者把握住它。