fun login(user: String, password: String, illegalStr: String) {  fun validate(value: String, illegalStr: String) { if (value.isEmpty()) { throw IllegalArgumentException(illegalStr) } }  validate(user, illegalStr) validate(password, illegalStr) }

这里我们将共同的验证逻辑放进了嵌套函数 validate 中,并且 login 函数之外的其他地方无法访问这个嵌套函数。

这里的 illegalStr 是通过参数的方式传进嵌套函数中的,其实完全没有这个必要,因为嵌套函数中可以访问在它外部的所有变量或常量,例如类中的属性、当前函数中的参数与变量等。

我们稍加改进:

️ fun login(user: String, password: String, illegalStr: String) { fun validate(value: String) { if (value.isEmpty()) {  throw IllegalArgumentException(illegalStr) } } … }

这里省去了嵌套函数中的 illegalStr 参数,在该嵌套函数内直接使用外层函数 login 的参数 illegalStr。

上面 login 函数中的验证逻辑,其实还有另一种更简单的方式:

️ fun login(user: String, password: String, illegalStr: String) { require(user.isNotEmpty()) { illegalStr } require(password.isNotEmpty()) { illegalStr } }

其中用到了 lambda 表达式以及 Kotlin 内置的 require 函数,这里先不做展开,之后的文章会介绍。

字符串

讲完了普通函数的简化写法,Kotlin 中字符串也有很多方便写法。

字符串模板

在 Java 中,字符串与变量之间是使用 + 符号进行拼接的,Kotlin 中也是如此:

️ val name = “world” println("Hi " + name)

但是当变量比较多的时候,可读性会变差,写起来也比较麻烦。

Java 给出的解决方案是 String.format:

☕️ System.out.print(String.format(“Hi %s”, name));

Kotlin 为我们提供了一种更加方便的写法:

️ val name = “world” //  用 ‘$’ 符号加参数的方式 println(“Hi $name”)

这种方式就是把 name 从后置改为前置,简化代码的同时增加了字符串的可读性。

除了变量,$ 后还可以跟表达式,但表达式是一个整体,所以我们要用 {} 给它包起来:

️ val name = “world” println(“Hi ${name.length}”)

其实就跟四则运算的括号一样,提高语法上的优先级,而单个变量的场景可以省略 {}。

字符串模板还支持转义字符,比如使用转义字符 \n 进行换行操作:

️ val name = “world!\n” println(“Hi $name”) //  会多打一个空行

字符串模板的用法对于我们 Android 工程师来说,其实一点都不陌生。

首先,Gradle 所用的 Groovy 语言就已经有了这种支持:

def name = “world” println “Hi ${name}”

在 Android 的资源文件里,定义字符串也有类似用法:

Hi %s

☕️ getString(R.id.hi, “world”);

raw string (原生字符串)

有时候我们不希望写过多的转义字符,这种情况 Kotlin 通过「原生字符串」来实现。

用法就是使用一对 """ 将字符串括起来:

️ val name = “world” val myName = “kotlin”  val text = “”" Hi $name! My name is $myName.\n “”" println(text)

这里有几个注意点:

\n 并不会被转义最后输出的内容与写的内容完全一致,包括实际的换行$ 符号引用变量仍然生效

这就是「原生字符串」。输出结果如下:

Hi world! My name is kotlin.\n

但对齐方式看起来不太优雅,原生字符串还可以通过 trimMargin() 函数去除每行前面的空格:

️ val text = “”"  |Hi world! |My name is kotlin. “”".trimMargin() println(text)

输出结果如下:

Hi world! My name is kotlin.

这里的 trimMargin() 函数有以下几个注意点:

| 符号为默认的边界前缀,前面只能有空格,否则不会生效输出时 | 符号以及它前面的空格都会被删除边界前缀还可以使用其他字符,比如 trimMargin("/"),只不过上方的代码使用的是参数默认值的调用方式

字符串的部分就先到这里,下面来看看数组与集合有哪些更方便的操作。

数组和集合

数组与集合的操作符

在之前的文章中,我们已经知道了数组和集合的基本概念,其实 Kotlin 中,还为我们提供了许多使数组与集合操作起来更加方便的函数。

首先声明如下 IntArray 和 List:

️ val intArray = intArrayOf(1, 2, 3) val strList = listOf(“a”, “b”, “c”)

接下来,对它们的操作函数进行讲解:

forEach:遍历每一个元素

️ //  lambda 表达式,i 表示数组的每个元素 intArray.forEach { i -> print(i + " ") } // 输出:1 2 3

除了「lambda」表达式,这里也用到了「闭包」的概念,这又是另一个话题了,这里先不展开。

filter:对每个元素进行过滤操作,如果 lambda 表达式中的条件成立则留下该元素,否则剔除,最终生成新的集合

️ // [1, 2, 3] ⬇️ // {2, 3}

//  注意,这里变成了 List val newList: List = intArray.filter { i -> i != 1 //  过滤掉数组中等于 1 的元素 }

map:遍历每个元素并执行给定表达式,最终形成新的集合

️ // [1, 2, 3] ⬇️ // {2, 3, 4}

val newList: List = intArray.map { i -> i + 1 //  每个元素加 1 }

flatMap:遍历每个元素,并为每个元素创建新的集合,最后合并到一个集合中

️ // [1, 2, 3] ⬇️ // {“2”, “a” , “3”, “a”, “4”, “a”}

intArray.flatMap { i -> listOf(“${i + 1}”, “a”) //  生成新集合 }

关于为什么数组的 filter 之后变成 List,就留作思考题吧~

这里是以数组 intArray 为例,集合 strList 也同样有这些操作函数。Kotlin 中还有许多类似的操作函数,这里就不一一列举了。

除了数组和集合,Kotlin 中还有另一种常用的数据类型: Range。

Range

在 Java 语言中并没有 Range 的概念,Kotlin 中的 Range 表示区间的意思,也就是范围。区间的常见写法如下:

️   val range: IntRange = 0…1000

这里的 0..1000 就表示从 0 到 1000 的范围,包括 1000,数学上称为闭区间 [0, 1000]。除了这里的 IntRange ,还有 CharRange 以及 LongRange。

Kotlin 中没有纯的开区间的定义,不过有半开区间的定义:

️  val range: IntRange = 0 until 1000

这里的 0 until 1000 表示从 0 到 1000,但不包括 1000,这就是半开区间 [0, 1000) 。

Range 这个东西,天生就是用来遍历的:

️ val range = 0…1000 //  默认步长为 1,输出:0, 1, 2, 3, 4, 5, 6, 7…1000, for (i in range) { print("$i, ") }

这里的 in 关键字可以与 for 循环结合使用,表示挨个遍历 range 中的值。关于 for 循环控制的使用,在本期文章的后面会做具体讲解。

除了使用默认的步长 1,还可以通过 step 设置步长:

️ val range = 0…1000 //  步长为 2,输出:0, 2, 4, 6, 8, 10,…1000, for (i in range step 2) { print("$i, ") }

以上是递增区间,Kotlin 还提供了递减区间 downTo ,不过递减没有半开区间的用法:

️ //  输出:4, 3, 2, 1, for (i in 4 downTo 1) { print("$i, ") }

其中 4 downTo 1 就表示递减的闭区间 [4, 1]。这里的 downTo 以及上面的 step 都叫做「中缀表达式」,之后的文章会做介绍。

Sequence

在上一期中我们已经熟悉了 Sequence 的基本概念,这次让我们更加深入地了解 Sequence 序列的使用方式。

序列 Sequence 又被称为「惰性集合操作」,关于什么是惰性,我们通过下面的例子来理解:

️ val sequence = sequenceOf(1, 2, 3, 4) val result: List = sequence .map { i -> println(“Map $i”) i * 2 } .filter { i -> println(“Filter $i”) i % 3 == 0 }  println(result.first()) //  只取集合的第一个元素

惰性的概念首先就是说在「」标注之前的代码运行时不会立即执行,它只是定义了一个执行流程,只有 result 被使用到的时候才会执行 当「」的 println 执行时数据处理流程是这样的: 取出元素 1 -> map 为 2 -> filter 判断 2 是否能被 3 整除 取出元素 2 -> map 为 4 -> filter 判断 4 是否能被 3 整除 …

惰性指当出现满足条件的第一个元素的时候,Sequence 就不会执行后面的元素遍历了,即跳过了 4 的遍历。

而 List 是没有惰性的特性的:

️ val list = listOf(1, 2, 3, 4) val result: List = list .map { i -> println(“Map $i”) i * 2 } .filter { i -> println(“Filter $i”) i % 3 == 0 }  println(result.first()) //  只取集合的第一个元素

包括两点:

声明之后立即执行数据处理流程如下:{1, 2, 3, 4} -> {2, 4, 6, 8}遍历判断是否能被 3 整除

Sequence 这种类似懒加载的实现有下面这些优点:

一旦满足遍历退出的条件,就可以省略后续不必要的遍历过程。像 List 这种实现 Iterable 接口的集合类,每调用一次函数就会生成一个新的 Iterable,下一个函数再基于新的 Iterable 执行,每次函数调用产生的临时 Iterable 会导致额外的内存消耗,而 Sequence 在整个流程中只有一个。

因此,Sequence 这种数据类型可以在数据量比较大或者数据量未知的时候,作为流式处理的解决方案。

条件控制

相比 Java 的条件控制,Kotlin 中对条件控制进行了许多的优化及改进。

if/else

首先来看下 Java 中的 if/else 写法:

☕️ int max; if (a > b) { max = a; } else { max = b; }

在 Kotlin 中,这么写当然也可以,不过,Kotlin 中 if 语句还可以作为一个表达式赋值给变量:

️  val max = if (a > b) a else b

另外,Kotlin 中弃用了三元运算符(条件 ? 然后 : 否则),不过我们可以使用 if/else 来代替它。

上面的 if/else 的分支中是一个变量,其实还可以是一个代码块,代码块的最后一行会作为结果返回:

️ val max = if (a > b) { println(“max:a”) a //  返回 a } else { println(“max:b”) b //  返回 b }

when

在 Java 中,用 switch 语句来判断一个变量与一系列值中某个值是否相等:

☕️ switch (x) { case 1: { System.out.println(“1”); break; } case 2: { System.out.println(“2”); break; } default: { System.out.println(“default”); } }

在 Kotlin 中变成了 when:

️  when (x) {  1 -> { println(“1”) } 2 -> { println(“2”) }  else -> { println(“else”) } }

这里与 Java 相比的不同点有:

省略了 case 和 break,前者比较好理解,后者的意思是 Kotlin 自动为每个分支加上了 break 的功能,防止我们像 Java 那样写错Java 中的默认分支使用的是 default 关键字,Kotlin 中使用的是 else

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)

一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!

AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算

纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android) [外链图片转存中…(img-1uDF0Ca3-1712584151826)]

一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!

AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算

推荐文章

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。