进阶Kotlin开发? 那不妨看看这本书
一、第一次在公众号推广告? (这是认真的吗)

依稀记得有很多小伙伴在公众号给我留言说我的公众号算是技术圈内一股清流,没有广告只要干巴巴的技术文章,希望我以后继续保持。(这一点请放心,我始终会牢记的,与大家没有好处的东西,绝对不往上发的)
说下背景吧,大概前些天华章的主编郭老师找到我,他热情地向我推荐了这本《Kotlin核心编程》,其实当时的心情真的挺纠结的,不太想在公众号打广告,他说请我先看看这本书,如果觉得好就帮忙推荐下。记得当时的回复是想先好好看这本书,看完后我想写一些真实想法和客观评价。所以第一时间拿到样书后,就开始在看这本书,到现在为止已经看了一大半了。看到现在感觉这本书是 真的既有广度也有深度,而且几乎每个知识点都会与Java和Kotlin进行对比,甚至还会Scala语法进行对比 。所以这一次我是真心想把这本书推荐给大家,当然啦还有赠书福利,一来也非常感谢大家一直的支持~~~,希望后面能给大家带来更多类似赠书福利活动。

二、推出今天的主角: 《Kotlin核心编程》
下面我会从几个方面来谈谈我对这本书看法
三、这本书适合哪些人看?
个人不推荐Kotlin的小白或新手直接看这本书,更适合已经有一定Kotlin开发基础和开发实战经验并且想进阶Kotlin开发的开发者。因为这本书定位不是在教你如何去基础使用Kotlin语法,它更多是在讲Kotlin这门语言设计的哲学和语法糖背后原理以及这个语法点为什么要这样设计。看过我之前文章小伙伴们就知道,我更习惯于分析Kotlin语法糖背后原理,每次分析完后,都不得不为Kotlin语言设计巧妙之处所折服。所以要想进一步探索Kotlin开发,那就努力去探索Kotlin的本质吧。
如果你是Kotlin小白,我更愿意推荐你去看Kotlin官方文档。如果英语能力有限,可以去看Kotlin中文社区中文站有官方文档的翻译。看完这些文档,可以去写一些例子,然后再来看这本书你会收获更多,而且不至于看不太懂。
四、该如何去看这本书
这本书 总共有13个章节 ,章节排序从Kotlin基本语法、面向对象、模式匹配、类型系统到注解反射、函数式编程、设计模式、并发异步和协程。
个人觉得看这本书顺序没必要按次序来看,如果你有一定Kotlin的基础的话,可以不用按照章节排序一节一节来看,完全可以按照你自己想看的知识点来看。比如说你现在在看Kotlin中泛型语法点,看完官方文档心里有种不痛不痒的感觉,比较空洞不容易理解的时候,你完全可以直接来看这门书中的类型系统这章,从最开始类、类型、子类型、可空类型、非空类型这些基本的概念由浅入深的系统全面地把Kotlin类型系统、泛型搞懂搞透。因为官方文档最多会教你怎么做,而这本书更多时候告诉你为什么要这样,这样设计原理又是什么。
四、这本书吸引我的几个小细节
-
细节一: 合理地把泛型相关内容放到类型系统章节后面
可能有的小伙伴就不理解了,这有什么。其实如果看过我之前泛型文章的小伙伴就知道我在讲Kotlin泛型之前,引出了很多概念: 比如 类与类型区别、子类与子类型的区别、超类和超类型的区别、什么是子类型化关系 ,然而这些概念只有类型系统中才会有。但是在泛型中理解子类型和子类型化关系是理解泛型逆变、协变的必要基础,如果没有提前灌输和理解这些概念,那么理解泛型相关的知识就比较吃力。
所以我特别赞本书作者把泛型纳入到类型系统这一章节,可以让读者直接从最基础概念,一步步由浅入深地理解类型系统和泛型。这说明作者的Kotlin知识点能力还是很强的,因为它可以从全局的角度去合理搭配有联系的知识点内容。其实我们潜意识里对知识的认知更深的最佳方式就是在脑中形成一张知识网;那么没有太大跳跃性断层的知识点将会更有助于你形成这张知识网;不至于那么零散,零散的知识更容易遗忘,而且需要花更多额外时间重新组织知识网。所以书中章节的内容点搭配组合往往也是非常重要的。
-
细节二: 合理地把内联函数放在lambda章节后面,而且同时放在一起分析内联函数两大作用。
首先,我们知道内联函数在Kotlin中有两大作用: 一种是优化Lambda的性能开销,另一种就是配合reified关键字实化参数类型,在某些地方可以解决Java泛型擦除的问题 ,这本书也非常合理地把这两种作用的分析阐述放在一起。如果你看过Kotlin in Action这本书,你就会发现这本书就内联函数作用的分析拆得比较散,分配在两个不同章节(一个是优化Lambda的性能开销放在高阶函数那章,另一是实化参数类型的放在了泛型那章),个人觉得这样会读者理解起来知识点比较散,没有这种一下子把东西介绍全面完整来得好。
-
细节三: 加入Java、Scala语言特性和Kotlin的对比
当你拿到这本书的时候,大概翻下就知道里面有很多Kotlin语法点和Scala语言、Java8的对比。我们都知道Kotlin这门语言借鉴了很多的Scala的语言特性。所以当时心里想作者不会为了赶时髦硬生生加上去的吧;其实不然,这本书的作者水滴团队人家最早之前就是玩Scala的,他们出了大量有关Scala的干货文章以及外文翻译。这不为了调查清楚点,我把他们博客地址都搬出来供大家参考: https://scala.cool/ ,所以觉得他们在Kotlin和Scala一定有自己独到见解,绝对不是为了赶时髦硬生生加上去的。
比如模式匹配那章处理嵌套表达式的模式匹配, 作者对比了Kotlin与Scala,发现Kotlin在模式匹配支持程度上并不像Scala那么好。比如书中处理一个整数表达式计算的基本需求的例子,首先定义如下结构:
sealed class Expr { data class Num(val value: Int): Expr()//Num类就是描述一个表达式中的某个整数的数值 data class Operate(val opName: String, val left: Expr, val right: Expr): Expr()//Operate类则表示一种二叉树树形结构,用于表示一些复杂的表达式 }
现在只需要实现一个很简单的功能就是,比如 “2 + 0”可以简化为2,引申一下就是“x + 0”或者“0 + x”可以简化为x. 面对这么简单需求我们第一想到就是写下如下伪代码:
//意思就是表达式如果是"x + 0" 或者 "0 + x"这两种模式就返回x否则就返回expr if(expr is "x + 0" || expr is "0 + x") x else expr
先来看下在Kotlin该如何实现呢? 一般的我们都会想到使用when表达式+递归方式来做的,像下面这样:
fun simplifyExpr(expr: Expr): Expr = when (expr) { is Expr.Num -> expr is Expr.Operate -> when (expr) { Expr.Operate("+", Expr.Num(0), expr.right) -> simplifyExpr(expr.right) Expr.Operate("+", expr.left, Expr.Num(0)) -> expr.left else -> expr } }
然后再一起来看下scala的实现:
sealed trait Expr case class Num (value: Int) extends Expr case class Operate(opName: String, left: Expr, right: Expr) extends Expr def simplifyExpr(expr: Expr): Expr = expr match { case Operate("+", Expr.Num(0), x) => x //0 +x case Operate("+", x, Expr.Num(0)) => x //x + 0 case _ => expr }
对比一下scala的实现非常简单,可以看到Kotlin在处理嵌套表达式并不能完全像scala那样做到严格意义上的模式匹配。它并不能像Scala的match-case那样,在匹配每一个分支的时候,先去判断该分支的类型。所以在Kotlin中必须还得加 is xxx
类型判断。
-
细节四: Kotlin独有的语法特性如何助力实现更优雅的设计模式
关注过我的公众号的小伙伴就知道我最近在写 Kotlin邂逅设计模式 这一系列的文章。然而这本书可以说是非常不错,里面介绍一些常用的设计模式,正好和我要写的内容不谋而合。Kotlin中设计模式的实现和Java的实现还是有很大的差别的,利用Kotlin语言自身的特性实现设计模式比硬生生套用Java中的设计模式实现要更优雅和更高效。
例如书中介绍的 使用命名参数和默认值参数来简化建造者模式 ,我们都知道在Java中使用建造者模式会引入Builder的概念而且需要写很多模板代码,又或者说你不知道 使用命名参数和默认值参数来简化建造者模式 ,可能还是会像Java那种思想引入Builder,即使你使用了Kotlin来编写你的代码依然无法解决代码优雅问题( 切记: 不要使用写Java那一套思想来写Kotlin代码,否则整个代码看起来就像是用机器翻译的一样,没有任何好处 )。然而合理地利用Kotlin自身特性就能轻松帮你摆脱模板代码。下面来看下两种Kotlin实现方式:
//利用java的思想来写Kotlin的代码的反例,切记不能这么干 class Robot private constructor( val code: String, val battery: String?, val height: Int?, val weight: Int? ) { class Builder(val code: String) { private var battery: String? = null private var height: Int? = null private var weight: Int? = null fun setBattery(battery: String?): Builder { this.battery = battery return this } fun setHeight(height: Int?): Builder { this.height = height return this } fun setWeight(weight: Int?): Builder { this.weight = weight return this } fun build(): Robot { return Robot(code, battery, height, weight) } } } //调用处 fun main(args: Array) { val robot = Robot.Builder("007") .setBattery("R6") .setHeight(100) .setWeight(80) .build() ... }
//使用命名参数和默认值参数来简化建造者模式 class Robot( val code: String, val battery: String? = null, val height: Int? = null, val weight: Int? = null ) //调用处 fun main(args: Array) { val robot1 = Robot(code = "007") val robot2 = Robot(code = "007", battery = "R6") val robot3 = Robot(code = "007", height = 100, weight = 60) }
对比上述两者实现方式,有没有觉得后者更像Kotlin,符合Kotlin的简洁、减少模板设计理念。可能有的人说使用方式发生变化,这就得从建造者模式中Builder的本质说起,Builder的本质就是模拟了具名可选参数,然而Kotlin自身语言就能轻松实现这个目的,岂不美滋滋。像这样减少模板代码设计模式还有很多很多,希望大家可以继续关注我后续文章讲解~~~
五、推荐几本其他书(大家如果觉得有需要也可以瞅瞅)
-
《深入理解Android:Java虚拟机ART》
关于这本我还是蛮推荐的,这本书的作者相信很多人都知道。他就是邓凡平老师,虽然书到了后我也没翻过多少页,但是我在网上看过很多邓老师的文章,特别很多有关虚拟机底层的文章,干货也是很满的。首先这门书是真的厚,里面有很多有关Android ART底层C++源码分析内容,而且很多分析流程都以代码注释和流程图的形式展现出来。所以这本书的出现算是填补了ART相关底层知识空白吧,不过我个人觉得有必要好好研究下这本书。
-
下面两本书觉得有需要,也可以看看
六、重点来了,发福利啦~~~

首先呢,很抱歉这次给大家拿到赠书名额不多,就 两个赠书名额 ,送点啥好呢??? 赠送的当然是我们今天的主角: 《Kotlin核心编程》 。送书名额实在是有限,先到先得,希望下次可以给小伙伴多争取点。如果想要的这本书的小伙伴欢迎下方留言, 留言点赞数前2名的小伙伴就可以免费拿到这本书了,截止时间是6月12日晚上8点公布名单 。