# 开篇词 | 入门Kotlin有多容易,精通Kotlin就有多难 你好,我是朱涛,欢迎和我一起学习Kotlin。 作为一名Kotlin、Android领域的谷歌开发者专家,我曾经负责过陌陌创新业务的Android客户端。从2017年开始,我和我的团队成员们就一直在探索Kotlin在Android中的应用,并在Kotlin函数式编程、Kotlin DSL、Kotlin协程以及Android Jetpack方面积累了一些实践经验。我的博客“Kotlin Jetpack实战”也影响和帮助了数万名Kotlin、Android开发者。 Kotlin于我来说,就如恋人一般,令我深深地着迷。在过去的5年里,我一直在使用Kotlin进行Android研发的工作。但实际上,在使用Kotlin之前,我的主力语言是Java,那段时间,我负责过陌陌Android客户端的代码规范以及性能优化工作。在这段工作里,我见过各式各样的**Java烂代码**,有些烂代码是程序员主观疏忽写出来的,而还有些代码是业务本身复杂度决定的。那个时候,我就意识到了Java语言的一些缺陷。 * **语法表现力差。** 比如,Java 1.8之前不支持Lambda表达式,匿名内部的写法繁琐;在函数方面,不支持高阶函数,不支持参数默认值,也不支持函数命名参数。当我们需要在Java当中实现类似需求时,不得不自己寻求其他替代方案,这就进一步提高了开发难度,降低了开发效率。 * **可读性差,难维护。** 如果我们单独去看Java的每个语法表现力的问题,可能会觉得没什么大不了。然而,当这样的问题积少成多,并且随着工程复杂度的提升,语法表现力的问题会进一步演变成可读性问题、维护性问题。 举个例子,Java当中的Callback,如果只是一到两个Callback的嵌套,那么它还在容忍的范围内,一旦业务变得复杂,Callback嵌套超过3层,代码可读性就会急剧下降,而后的维护工作将会变成一场灾难!出现Bug,也只是迟早的问题。 * **Java自身的语法设计也使它更容易出错。** 比如,Java基础类型的隐式转换,你可以直接将字符变量赋值给整型变量,而编译器也不会报错。再比如,Java的内部类会偷偷持有外部类的引用,从而在某些场景中导致内存泄漏。Java这样的语法设计就让我们程序员更容易写出Bug。 * **并发编程,在Java当中也是一大难题。** 在Java当中,线程与并发以及它复杂的同步机制,它们就像是一头头难以驯服的野马,初中级Java程序员都会对其望而生畏。 以上Java的所有缺陷,最终反映到实际工作中,就会变成:**前期开发效率低,中期线上问题多,后期代码难维护。**其实,归根结底,都是因为Java实在是太老了。而Kotlin作为一门刚出生不久的语言,就是为了解决这些问题而生的。 在与Kotlin相伴5年的过程中,我一直在研究、探索这门语言的原理和使用技巧,也沉淀了一些实践经验和思考感悟,希望通过这门课,能给你带来一些新的有关Kotlin的认知以及使用参考,也能够让你在学习之后,可以使用Kotlin来解决工作中的实际问题。 ## Kotlin为什么值得学? 其实,不管你之前是不是有过Java的使用经验,你都需要来学习一下这门年轻的语言。我认为主要有这样三个原因。 **第一,极高的生产效率** Kotlin具备简洁的语法和现代化的语法特性,让使用者可以用更少的时间,以更高的标准,来完成更多的工作。换句话说,也就是跟Java正好相反:前期开发效率更高,中期线上问题更少,后期代码更容易维护。 以我自身为例,在我们团队完全适应了Kotlin的开发节奏以后,线上崩溃率就大大降低了,而空指针异常也几乎没有了。另外,曾经要3人完成的工作,在使用Kotlin以后,2个人就能完成,而且还能完成得更好。 为此,不仅各个大厂的Android部门在积极转型,就连Android官方团队也都在用Kotlin写底层的源码,Kotlin相关的SDK也层出不穷。到目前为止,各个大厂的Android招聘要求里都会加上一条“要求熟悉Kotlin”或“熟悉Kotlin语言者优先”。 **第二,强大的兼容性** Kotlin可以与Java混合编程,这一点尤为重要,不然,Kotlin的吸引力将大打折扣。因为在我们的实际工作当中,大部分情况都是在老旧工程的基础上去开发新功能的,而将整个模块甚至是程序推倒然后用Kotlin重写,其实是很不现实的。 Kotlin强大的兼容性,就让我们可以复用从前的Java代码,也能让我们以渐进的方式从Java迁移到Kotlin,而不必担心是不是要一次性重写很多代码,从而产生新的问题。 **第三,科技巨头加持,Kotlin的发展前景很广阔** 2017年,Google宣布Kotlin成为Android的官方语言后,人们对于Kotlin的关注度就一直在上升。而这也就导致,很多人听到Kotlin,都会下意识地认为它是用来写Android的。 其实,Kotlin不仅仅只是在Android领域有所建树,据我所知,[Amazon](https://talkingkotlin.com/qldb)、[Adobe](https://medium.com/adobetech/streamlining-server-side-app-development-with-kotlin-be8cf9d8b61a)都有将Kotlin应用到后端开发;至于Kotlin跨平台方面,国际上[Philips](https://kotlinlang.org/lp/mobile/case-studies/philips)、[Square](https://kotlinlang.org/lp/mobile/case-studies/cash-app)等公司也都有不错的实践,国内的携程技术团队在这方面也有不少探索和实践。随着2021年Android Jetpack Compose的发布,JetBrains在其基础上又扩展出了[Compose-jb](https://github.com/JetBrains/compose-jb),让Kotlin还能跨平台编写UI界面。 总而言之,对于Android开发者来说,Kotlin已是**必学**的编程语言;而对于其他领域的开发者来说,Kotlin也有着非常好的前景,现在入坑还来得及! ## Kotlin到底难在哪? 那么,在看到了Kotlin有如此多的使用优势和如此广阔的发展前景之后,也有不少人都纷纷投入了Kotlin的学习大军当中,甚至很多人都是在有了Java的知识基础和使用经验之后,再去学习的Kotlin,而且他们会觉得,Kotlin的学习很简单,它跟Java的很多语法都是一样的,没啥难的嘛。 但其实,这是对Kotlin的一种误解。**带着Java经验学习Kotlin,这既是一种助力,同时也是一种阻碍。**在Kotlin学习的前期,Java经验可以帮我们快速掌握它的语法,但到了后期,我们脑子里的Java老一套会限制我们进一步提升。如果我们迟迟不转变自己的思维,只会在Kotlin学习之路上越跑越偏。 从我的实践经验来看,Java开发者学习Kotlin的难点,主要在于**思维的转变**: * **不变性思维**,虽然Java当中也存在final不变性,然而,Kotlin却将这件事做到了极致:Kotlin要求我们在定义一个变量、集合的时候,就明确规定它的不变性。Kotlin这样的设计,就是希望在软件当中尽可能地消灭可变性。如果我们脑子里没有不变性思维,我们写出来的Kotlin代码将“惨不忍睹”。 * **空安全思维**,Kotlin的类型系统分为可空和不可空类型,这样的设计也彻底改变了我们的编程习惯。想要处理好Kotlin的空安全问题,我们也必须完成思维的转变。 * **表达式思维**,在Kotlin当中,if、else、when之类的语句,还能作为表达式来使用,这样的语法特性往往可以帮我们简化代码逻辑。 * **函数思维**,在Kotlin当中,函数是一等公民。Kotlin也是一门积极拥抱函数式编程的语言,在Kotlin的一些语法设计上,总能看到一些函数式的影子。命令式编程与函数式编程,它们两者有各自的优缺点,也有各自擅长的领域。而Kotlin除了有命令式的一面,对应地,它还有函数式的一面。 * **协程思维**,Java开发者在学习Kotlin协程的时候尤为痛苦,因为,在Java开发者脑子里只有“线程思维”,而对协程一无所知。想要真正地理解和掌握Kotlin的协程,我们需要从根本上改变我们脑子里的思维模型。 Java开发者学习Kotlin很难,那么零基础学习Kotlin会不会更简单呢?毕竟不存在旧思维束缚啊! 其实不然,零基础,也就意味着编程经验的欠缺。因此,零基础学习Kotlin最大的问题在于:**容易浮于Kotlin语法表面,体会不到Kotlin设计的美感,悟不出Kotlin特性的应用场景,看不到Kotlin底层的实现原理。** 不过,请放心,以上所有的问题,在这门课当中,都会得到解决。 除了以上的学习难点以外,Kotlin本身的学习曲线和其他的语言不太一样,它是一门**易学难精**的语言。Kotlin的语法非常简洁,确实极其容易入门;但同时,它又拥有许多的新特性,不容易掌握。**即使你掌握了Kotlin的一个个语法,想要写出优雅的Kotlin代码,仍然不是一件容易的事情。** 我凭啥这么说呢?让我从自己学习Kotlin的经历说起。 ![图片](https://static001.geekbang.org/resource/image/2e/d0/2ea3975d4dccc3dbab871d50eab171d0.jpg?wh=1920x1013) 从我的亲身经历来看,我的Kotlin学习之路大致分为三个阶段: * **第一阶段,初窥门径。** 由于Kotlin的语法非常简单,刚开始我非常自信,在学完基础语法以后,就开始试着以Java的思维写Kotlin代码,而Kotlin独有的特性,我却很少用到。渐渐地,我发现了不对劲的地方:因为我**并没有发挥出Kotlin的简洁与高效的优势**。同时,我内心的自信,也逐渐变成了迷茫。我终于知道,自己对Kotlin的理解还非常得浅显。 * **第二阶段,登堂入室。** 这时候,难度就上来了,我开始钻研Kotlin的一些新特性的原理,并且研究它们的使用场景。在这个过程中,随着我对Kotlin的理解的深入,我也真切地感受到了Kotlin语法的美感,同时,也深深地爱上了Kotlin这门语言。这时候,我终于登堂入室了。 * **第三阶段,豁然开朗。** 当我觉得自己对Kotlin已经足够了解的时候,我决定学习Kotlin的协程。这时候,我几乎绝望了。面对一堆全新的概念,我几乎毫无头绪:协程、作用域、上下文、launch、async、Channel、Flow、异常处理,我完全不知该如何入手。我一边研究协程源码、一边在工作中实践,这一路,我踩过不少坑,也引发过线上故障,磕磕碰碰之间,忽然有一天,量变产生了质变,我终于感觉豁然开朗,前方一片坦途。 现在回过头来看,当初我的Kotlin学习之路是**艰难且曲折**的。主要还是因为那时候,优质的Kotlin学习资源不多,且不成体系。大家都是跟着官方文档自学,而Kotlin官方文档对初学者又不那么友好,因此只能“摸着石头过河”。 由于我曲折的Kotlin学习经历,这也决定了我们这门课会力求**简单易懂**。比如,为了让你理解Kotlin的扩展函数的使用场景,我精心制作了普通函数与扩展函数的转换动画: ![图片](https://static001.geekbang.org/resource/image/ee/43/ee2570eb0a1b10155ecf34bd7f291343.gif?wh=720x405) 另外,**协程一直都是Kotlin学习的难点。**在过去这几年的研究中,我总结出了一套“**协程思维模型**”。在我写协程代码的时候,我的大脑里会有一套对应的模型,来帮我模拟协程的运行过程。而这些,我也会在这门课中,以最直观的方式传授给你。 比如,下面这张图就展示了协程、线程与进程之间的关系。它能帮你在大脑里建立一个清晰、具体的协程模型。 ![图片](https://static001.geekbang.org/resource/image/31/9d/31f035dc1b008be1912b3e221e505f9d.gif?wh=720x405) 再比如说,为了让你看到协程代码背后**挂起与恢复**的细节,我精心制作了这个示意图。它可以让你对协程挂起函数有一个更深入的认识。 ![图片](https://static001.geekbang.org/resource/image/6b/2b/6b772a6ef97e6b5587690d10a8f5bb2b.gif?wh=720x405) 当然,动画解析只是一种讲述方式,我选这种方式,只是因为它最直观。咱们这门课程的核心理念还是:**帮你快速掌握Kotlin的核心知识点,理解Kotlin的编程思想,最终可以用漂亮的Kotlin代码,来解决工作中的问题。** ## 怎么学习Kotlin? Kotlin当中涵盖了很多新的语言特性,要学会这些新特性的语法其实很简单,但是要理解Kotlin设计这些新特性背后的意图,却不容易。而这,恰好就是我们需要重点关注的地方。因为,只有当我们知道Kotlin为什么要设计这些新特性,我们才能弄清楚这些特性的最佳使用场景。 ![图片](https://static001.geekbang.org/resource/image/f6/9d/f65548f66702b86a7aa4433aeeea319d.jpg?wh=1920x1315) 所以在课程中,我会尽量去揣测Kotlin设计者的思路,去对比Kotlin和Java语法的差异,然后用一些实际案例来给你讲解Kotlin新特性的使用场景。具体来看,这个课程主要分为四个部分。 * **基础篇** 这个模块,我们会集中精力攻克Kotlin的核心语法,包括基础语法、面向对象、高阶函数、扩展、委托、泛型、注解和反射。并且,每学习三到四个语法,我们就会通过一个**实战项目**将这些知识点串联起来,从而达到学以致用的目的。 * **协程篇** 协程,是Kotlin当中极其重要的特性,同时它也是Kotlin当中极其难学的特性。在这个模块,我会深入讲解协程当中的各个概念,并且会给你介绍协程的思维模型,**帮助****你****完成“线程思维”到“协程思维”的转换**。当然了,在这个过程中,我也会结合实战项目,让你能上手体验协程的魅力。 * **源码篇** 在理解了前两个模块的内容之后,你就算是初步掌握Kotlin这门语言了。不过,我们不仅**要知其然,还要知其所以然**。 Kotlin官方的源代码其实是一座宝库,里面充满了Kotlin的最佳实践。通过研究Kotlin的源代码,我们可以进一步加深对Kotlin理解,同时,也可以去探究它底层的原理。比如,Kotlin协程的挂起函数到底是如何挂起的?Kotlin协程到底是如何与线程衔接的?这些问题,我都会在这个模块,用尽量简单的方式解释给你听。 * **Android项目篇** 目前来说,Kotlin最主要的应用还是在Android领域。因此,在学完前面几个模块以后,我们再来看看Kotlin在Android领域到底能做什么。Kotlin凭什么能被Google指定为“官方语言”?如何使用Kotlin来提升开发效率?如何将Kotlin的特性融入到Android的架构设计中?最后,我也会带你一起来**用Kotlin写一个简单的Android App**。 除此之外,我还会不定期进行**加餐**,给你分享Kotlin在各个领域的一些知识,来进一步扩展你的Kotlin知识面。比如,Kotlin协程在后端、Android端的应用,Kotlin Multiplatform在跨平台当中的应用,以及Compose在UI领域的应用。 ![](https://static001.geekbang.org/resource/image/1a/eb/1a1a47b704fc22ec6646b43b8fd7a4eb.jpg?wh=1564x8151) 从课程安排上,相信你已经明白了:这是一个理论与实战结合的课程。因此,在学习的过程中,我希望你能够一边学习,一边跟着我完成课程配套的实战项目。另外,如果你在学习的过程中有了一些新的感悟,也欢迎你将其以博客、部落、留言评论等形式发表出来,分享给更多的人。还有一点是:如果你有不懂的地方,一定要在评论区讲出来,我们一起交流。 你可以自己立个Flag,每节课都在评论区分享思考题的思路。我相信,几个月后,你一定会有巨大的提升。 最后,希望你也可以和我一样,爱上Kotlin。