Kotlin编程第一课--(协程篇)15 挂起函数:Kotlin协程的核心
这节课,我们来学习协程的挂起函数。
挂起函数,是 Kotlin 协程当中最基础、最重要的知识点。如果对协程的挂起函数没有足够的认识,我们后续的学习将会困难重重。如果不理解挂起函数,我们将无法理解协程的非阻塞;如果不了解挂起函数,我们将无法掌握 Channel、Flow 等 API;如果不理解挂起函数,我们写出来的代码也会漏洞百出,就更别提优化软件架构了。
相反,如果能将挂起函数理解透彻,我们后面的学习也会更加轻松一些。所以这节课,我会从应用和原理两个角度,来带你理解挂起函数,包括如何使用挂起函数来优化异步任务,以及挂起函数的 CPS 当中的 Continuation 到底是什么。通过对这两个维度的学习,你在更轻易地掌握挂起函数应用场景的同时,对它的底层原理也会有一定认识。
那么接下来,你一定要打起精神,我们一起来攻克这个关键的知识点!
挂起函数:Kotlin 协程的优势通过前面课程的学习,我们已经知道了:协程就像是轻量级的线程一样。用线程能实现的功能,我们借助 launch 和 async 也同样可以做到。
不过你可能会好奇,如果只是把 thread{} 替换成 launch{},那协 ...
Kotlin编程第一课--(协程篇)14 如何启动协程?
从今天开始,咱们正式进入协程 API 的学习,一起来攻克 Kotlin 当中最关键的部分。这节课呢,我会给你介绍下如何启动协程,主要包括协程的调试技巧、启动协程的三种方式。这些都是学习协程最基本的概念,也是后续学习更多高阶概念的基础。
注意,在这节课当中,我会使用协程 API 编写大量的案例。我也希望你能够打开 IDE,跟着我一起来运行对应的代码。通过这样的方式,你一定会有更多的收获。
好,接下来,让我们直接开始学习吧!
协程调试想要学好 Kotlin 协程,掌握它的调试技巧很重要。一般来说,我们可以通过两种手段来进行调试:设置 VM 参数、断点调试。
协程 VM 参数我们先来看第一种。具体的做法呢,其实很简单,我们只需要将 VM 参数设置成“-Dkotlinx.coroutines.debug”。
完成这个设置后,当我们在 log 当中打印“Thread.currentThread().name”的时候,如果当前代码是运行在协程当中的,那么它就会带上协程的相关信息。具体我们可以看个代码的例子:
// 不必关心代码逻辑,关心输出结果即可fun main() { Glo ...
Kotlin编程第一课--(协程篇)13 什么是“协程思维模型”?
学完基础篇以后,相信现在你对 Kotlin 的基础语法和特性都有了全面的认识。那么从今天开始,我们就要进入一个新的模块,一起来学习 Kotlin 当中最重要、最难学,也是最受期待的特性——协程。
为什么协程如此重要?协程是 Kotlin 对比 Java 的最大优势,这也是我说协程是 Kotlin 中最重要特性的主要原因。虽说 Java 也在计划着实现自己的协程:Loom,不过这个毕竟还处于相当初级的阶段。而 Kotlin 的协程,可以帮我们极大地简化异步、并发编程、优化软件架构。通过协程,我们不仅可以提高开发效率,还能提高代码的可读性,由此也就可以降低代码出错的概率。
不过,遗憾的是,Kotlin 协程在业界的普及率并不高。因为,你如果对协程没有足够的认识,贸然在生产环境里使用协程,一定会遇到各种各样的问题,并要为之付出昂贵的代价(典型的反面例子就是滥用 GlobalScope,导致大量的计算资源浪费以及出现生命周期错乱的问题)。
Kotlin 的协程就是这样,表面上看,它的语法很简单,但行为模式却让人难以捉摸。举个简单的例子,同样是 5 行代码,普通的程序,这 5 行代码的运行顺序一 ...
Kotlin编程第一课--(特别放送)刷题计划(四) 一题三解,搞定分式加减法
在上节课里呢,我给你留了一个作业:用 Kotlin 来完成 LeetCode 的 592 号题《分数加减运算》。那么今天这节课,我们就一起来看看它的解题思路吧。
这其实也是一道典型的模拟题,分式的加减法这样的题目,我们小学就知道怎么做了,核心解题思路主要是这几步:
第一步,求出分母的最小公倍数。比如,2 和 3 的最小公倍数就是 6。
第二步,根据计算出来的最小公倍数,将分数进行通分。举个例子:“1/2-1/6”,如果把它们两个通分,就会变成“3/6-1/6”。
第三步,将分子进行加减法,计算出分子的结果。比如,“3/6-1/6”计算过后,就会变成“2/6”。
最后一步,将计算结果转换成“最简分数”,比如“2/6”化成最简分数以后,应该是“1/3”。
经过这四个步骤,我们就可以计算出“1/2-1/6=1/3”。不过呢,这道题里,我们除了要计算分数的加减法以外,还要先完成分数的解析。程序的输入是字符串“1/2-1/6”,但它是不会帮我们 ...
Kotlin编程第一课--(春节特别放松)春节刷题计划(三) 一题双解, 方程
在上节课里,我给你留了一个作业,那就是:用 Kotlin 来完成 LeetCode 的 640 号题《求解方程》。那么这节课,我就来讲讲我的解题思路,我们互相学习。
这道题也非常容易理解,程序的输入是一个“一元一次方程”,我们需要根据输入的方程,计算出正确的结果。根据输入方程的不同,结果可能有三种情况:
方程仅有一个解,这时,我们只需要按照格式返回结果即可,比如输入“2x=4”,那么输出就应该是“x=2”。
方程有无数个解,比如输入“x=x”,那么输出就应该是“Infinite solutions”。
方程无解,比如输入“x=x+5”,那么输出结果就应该是“No solution”。
另外,对于程序的输入格式,其实我们还有几个问题需要弄清楚。只有弄清楚了这些问题,我们才能开始写代码:
方程当中的未知数只会用 x 表示,不会是 y,也不会是大写的“X”。
方程当中不会出现空格,比如“2x=4”,不会出现“2x = 4 ”的情况。
方程当中只会有加减法,不会出现乘除法。
方程当中的数字,一定是整数,不会出现分数、小数。
输入 ...
Kotlin编程第一课--(特别放送)刷题计划(二) 一题三解,搞定版本号判断
在上节刷题课中,我给你留了一个作业,那就是:用 Kotlin 来完成 LeetCode 的 165 号题《版本号判断》。那么今天这节课,我就来讲讲我的解题思路,希望能给你带来一些启发。
这道题目其实跟我们平时的工作息息相关。给你两个字符串代表的版本号,需要你判断哪个版本号是新的,哪个版本号是旧的。比如,2.0 与 1.0 对比的话,2.0 肯定是新版本,1.0 肯定是旧版本。对吧?
不过,这里面还有一些问题需要留意,这些都是我们在正式写代码之前要弄清楚的。
首先,版本号是可能以 0 开头的。比如 0.1、1.01,这些都是合理的版本号。
另外,如果是以 0 开头的话,1 个 0 和多个 0,它们是等价的,比如 1.01、1.001、1.00001 之间就是等价的,也就是说这几个版本号其实是相等的。
还有,1.0、1.0.0、1.0.0.0 它们之间也是等价的,也就是说这几个版本号也是相等的。
思路一好了,理解了题意以后,我们就可以开始写代码了,LeetCode 上面给了我们一个待实现的方法,大致如下:
fun compareVersion(version1: String, ver ...
Kotlin编程第一课--(特别放送)刷题计划(一) 当Kotlin遇上LeetCode
时光飞逝,不知不觉间,我们就已经完成了基础篇的学习,并且也已经完成了三个实战项目,但这终归是不够过瘾的。想要完全掌握 Kotlin 的基础语法,我们还需要更多的练习。我相信,你现在的心情就像是一个手握屠龙刀的勇士,热切希望找一些对手来验证自己的学习成果。
其实,我自己在学习一门新的编程语言的时候,有一个高效的方法,也分享给你。这里我以 Kotlin 为例,假设我现在是一个新手,想快速掌握 Kotlin 的话,我会这样做:
第一步,我会去 Google 搜索一些语言特性对比的文章。比如,我熟悉 Java,想学 Kotlin,我就会去搜“from Java to Kotlin”,然后去看一些 Java、Kotlin 语法对比的文章。这时候,我大脑里就会建立起 Java 与 Kotlin 的语法联系。
第二步,我会打开Kotlin 官方文档,花几个小时的时间粗略看一遍,对 Kotlin 的语法有个大致印象。
最后一步,我会打开 LeetCode 之类的网站,开始用 Kotlin 刷题。在刷题的过程中,我也会先从模拟类的题目开始,之后再到数组、链表、Map、二叉树之类的数据结构。整个过程由易 ...
Kotlin编程第一课--(基础篇)加餐四 什么是“空安全思维”?
这节加餐,我们来聊聊空安全思维。
空(null),是很多编程语言中都有的设计,不同的语言中名字也都不太一样,比如 Java 和 Kotlin 里叫 null,在 Swift 里叫做 nil,而 Objective-C 当中,根据情况的不同还细分了 NULL、nil、Nil 等等。
如果你有 Java 的经验,那你一定不会对 NullPointerException(NPE,代码中常见的逻辑错误)感到陌生。null 会引起 NPE,但是在很多场景下,你却不得不使用它。因为 null 用起来实在是太方便了。比如说,前面第 4 讲里,我提到的计算器程序当中的 calculate() 方法,它的返回值就是可为空的,当我们的输入不合法的时候,calculate() 就会返回 null。
一般来说,我们会习惯性地用 null 来解决以下这些场景的问题:
当变量还没初始化的时候,用 null 赋值;
当变量的值不合法的时候,用 null 赋值;
当变量的值计算错误的时候,用 null 赋值。
虽然这些场景,我们不借助 null 也可以漂亮地解决,但 null 其实才是最方便的解决方案。因为总的来 ...
Kotlin编程第一课--(基础篇)加餐三 什么是“不变性思维”?
在开篇词里,我提到过学习 Kotlin 的五种思维转变,包括前面加餐中讲过的函数思维、表达式思维,以及接下来要给你介绍的不变性思维、空安全思维以及协程思维。所以今天,我们就一起来聊聊 Kotlin 的不变性思维。
Kotlin 将不变性的思想发挥到了极致,并将其融入到了语法当中。当开发者想要定义一个变量的时候,必须明确规定这个变量是可变的(var),还是不可变的(val)。在定义集合变量的时候,也同样需要明确规定这个集合是可变的(比如 MutableList),还是不可变的(比如 List)。
不过,不变性其实会被很多 Kotlin 初学者所忽略。尤其是有 Java、C 经验的开发者,很容易将老一套思想照搬到 Kotlin 当中来,为了方便,写出来的变量全部都是 var 的,写出来的集合都是 MutableXXX。
事实上,不变性思维,对我们写出优雅且稳定的 Kotlin 代码很关键。要知道,我们代码中很多的 Bug 都是因为某个变量被多个调用方改来改去,最后导致状态错误才出问题的。毕竟,变动越多,就越容易出错!
那么,既然可变性这么“可恶”,我们为何不干脆直接在语法层面消灭 var、 ...
Kotlin编程第一课--(基础篇)加餐二 什么是“表达式思维”?
在开篇词当中,我曾经说过,学好 Kotlin 的关键在于思维的转变。在上一次加餐课程当中,我给你介绍了 Kotlin 的函数式编程思想,相信你对 Kotlin 的“函数思维”已经有了一定的体会。那么今天这节课,我们就来聊聊 Kotlin 的表达式思维。
所谓编程思维,其实是一种非常抽象的概念,很多时候是只可意会不可言传的。不过,从某种程度上看,学习编程思维,比学习编程语法还要重要。因为编程思维决定着我们的代码整体的架构与风格,而具体的某个语法反而没那么大的影响力。当然,如果对 Kotlin 的语法没有一个全面的认识,编程思维也只会是空中楼阁。
所以,准确地来说,掌握 Kotlin 的编程思维,是在掌握了 Kotlin 语法基础上的一次升华。这就好比是,我们学会了基础的汉字以后开始写作文一样。学了汉字以后,如果不懂得写作的技巧,是写不出优美的文章的。同理,如果学了 Kotlin 语法,却没有掌握它的编程思维,也是写不出优雅的 Kotlin 代码的。
好,那么接下来,我们就来看看 Kotlin 的表达式思维。
表达式思维在正式开始学习表达式思维之前,我们先来看一段简单的 Kotlin 代码 ...