了解的变量和函数,接下来我们还需要懂得如何将他们更好的组合起来使用,这里就需要学习程序的执行语句了
程序的执行语句主要分为3种:顺序语句、条件语句和循环语句。顺序语句很好理解,就是代码一行一行地往下执行就可以了,但是这种“愣头青”的执行方式在很多情况下并不能满足我们的编程需求,这时就需要引入条件语句和循环语句了,下面我们逐个进行介绍。
1.if条件语句
Kotlin中的条件语句主要有两种实现方式:if和when。
首先学习if,Kotlin中的if语句和Java中的if语句几乎没有任何区别,因此这里我就简单举个例子带你快速了解一下。
这里以上一节中的test()【之后改成choicelarger(选择更大的)】函数为例,之前我们借助了Kotlin内置的max()函数来实现返回两个参数中的较大值,但其实这是没有必要的,因为使用if判断同样可以轻松地实现这个功能。将choicelarger()函数的实现(不使用max()函数)改成如下写法:
fun choicelarger(num1: Int, num2: Int): Int {
var value = 0
if (num1 > num2) {
value = num1
} else {
value = num2
}
return value
}
复制代码
这里通过if判断,如果num1大于num2.就执行value=num1的操作,否则就执行value=num2的操作
这有编程基础的理解应该都没问题,关于if更详细的介绍可以看 菜鸟教程中的条件控制的介绍
值得一提的是,这里使用了var关键字来声明value这个变量,这是因为初始化的时候我们先将value赋值为0,然后再将它赋值为两个参数中更大的那个数,这就涉及了重新赋值,因此必须用var关键字才行。
到目前为止,Kotlin中的if用法和Java中是完全一样的。但注意我前面说的是“几乎没有任何区别”。也就是说,它们还是存在不同之处的,那么接下来我们就着重看一下不同的地方。
Kotlin中的if语句相比于Java有一个额外的功能,它是可以有返回值的,返回值就是if语句每一个条件中最后一行代码的返回值。因此,上述代码就可以简化成如下形式(运行结果也是一样的,如下图1):
fun choicelarger(num1: Int, num2: Int): Int {
val value = if (num1 > num2) {
num1
} else {
num2
}
return value
}
复制代码
注意这里的代码变化,if语句使用每个条件的最后一行代码作为返回值,并将返回值赋值给了
value变量。由于现在没有重新赋值的情况了,因此可以使用val关键字来声明value变量,最
终将value变量返回。
仔细观察上述代码,你会发现value其实也是一个多余的变量,我们可以直接将if语句返回,这样代码将会变得更加精简,如下所示(编译之后结果也是一样的):
fun choicelarger(num1: Int, num2: Int): Int {
return if (num1 > num2) {
num1
} else {
num2
}
}
复制代码
到这里为止,你觉得代码足够精简了吗?确实还不错,但是我们还可以做得更好。回顾一下刚刚在上一节里学过的语法糖,当一个函数只有一行代码时,可以省略函数体部分,直接将这一行代码使用等号串连在函数定义的尾部。虽然上述代码中的choicelarger()函数不止只有一行代码,但是它和只有一行代码的作用是相同的(只有一条指令),只是返回了一下if语句的返回值而已,符合该语法糖的使用条件。那么我们就可以将代码进一步精简(如果用惯其它语言的人看这个会不会觉得很神奇):
fun choicelarger(num1: Int, num2: Int) = if (num1 > num2) {
num1
} else {
num2
}
复制代码
当然,如果你愿意,还可以将上述代码再精简一下,直接压缩成一行代码:
fun choicelarger(num1: Int, num2: Int) = if (num1 > num2) num1 else num2
复制代码
怎么样?通过一个简单的if语句,我们挖掘出了Kotlin这么多好玩的语法特性,现在你应该能逐渐体会到Kotlin的魅力了吧?
2.when条件语句
接下来我们开始学习when。Kotlin中的when语句有点类似于Java中的switch语句,但它又远比switch语句强大得多。
如果你熟悉Java的话,应该知道Java中的switch语句并不怎么好用。首先,switch只能传入整型或短于整型的变量作为条件,JDK 1.7之后增加了对字符串变量的支持,但如果你的判断逻辑使用的并非是上述几种类型的变量,那么不好意思,switch并不适合你。其次,switch中的每个case条件都要在最后主动加上一个break,否则执行完当前case之后会依次执行下面的case,这一特性曾经导致过无数奇怪的bug,就是因为有人忘记添加break。
而Kotlin中的when语句不仅解决了上述痛点,还增加了许多更为强大的新特性,有时候它比if
语句还要简单好用,现在我们就来学习一下吧。
编写一个查询考试成绩的功能,输入一个学生的姓名,返回该学生考试的分数。我们先用上一小节学习的if语句来实现这个功能,在LearnKotlin文件(之前新建的一个kt文件)中编写如下代码:
fun getScore(name: String) = if (name == "Tom") {
86
} else if (name == "Jim") {
77
} else if (name == "Jack") {
95
} else if (name == "Lily") {
100
} else {
0
}
复制代码
这里定义了一个getScore()函数,这个函数接收一个学生姓名参数,然后通过if判断找到该学生对应的考试分数并返回。可以看到,这里再次使用了单行代码函数的语法糖,正如上面所说,它真的很常用。
虽然上述代码确实可以实现我们想要的功能,但是写了这么多的if和else,你有没有觉得代码很冗余?没错,当你的判断条件非常多的时候,就是应该考虑使用when语句的时候,现在我们将代码改成如下写法:
fun getScore(name: String) = when (name) {
"Tom" -> 86
"Jim" -> 77
"Jack" -> 95
"Lily" -> 100
else -> 0
}
复制代码
同样,这个函数接收一个学生姓名参数,然后通过when判断找到该学生对应的考试分数并返回( 函数会返回输入的字符串(学生姓名)所匹配的数值(学生分数) ),更多关于when的用法可以看菜鸟教程中的Kotlin 条件控制介绍
怎么样?有没有感觉代码瞬间清爽了很多?另外你可能已经发现了,when语句和if语句一样,也是可以有返回值的,因此我们仍然可以使用单行代码函数的语法糖。
when语句允许传入一个任意类型的参数,然后可以在when的结构体中定义一系列的条件,格式是:
匹配值 -> { 执行逻辑 }
复制代码
当你的执行逻辑只有一行代码时,{ }可以省略。这样再来看上述代码就很好理解了吧?除了精确匹配之外,when语句还允许进行类型匹配。什么是类型匹配呢?这里我再举个例子。定义一个heckNumber()函数,如下所示:
fun checkNumber(num: Number) {
when (num) {
is Int -> println("number is Int")
is Double -> println("number is Double")
else -> println("number not support")
}
}
复制代码
上述代码中,is关键字就是类型匹配的核心,它相当于Java中的instanceof关键字。由于checkNumber()函数接收一个Number类型的参数,这是Kotlin内置的一个抽象类,像Int、Long、Float、Double等与数字相关的类都是它的子类,所以这里就可以使用类型匹配来判断传入的参数到底属于什么类型,如果是Int型或Double型,就将该类型打印出来,否则就打印不支持该参数的类型。
现在我们可以尝试在main()函数中调用checkNumber()函数,如下所示(运行结果见图一):
fun main() {
val num = 10
checkNumber(num)
}
fun checkNumber(num: Number) {
when (num) {
is Int -> println("number is Int")
is Double -> println("number is Double")
else -> println("number not support")
}
}
复制代码
可以看到,这里成功判断出了参数是Int类型。而如果我们将参数改为Long型(结果如下图1):
很显然,我们的程序并不支持此类型的参数。
when语句的基本用法就是这些,但其实when语句还有一种不带参数的用法 (when后面没有参数),虽然这种用法可能不太常用,但有的时候却能发挥很强的扩展性。拿刚才的getScore()函数举例,如果我们不在when语句中传入参数的话,还可以这么写:
fun getScore(name: String) = when {
name == "Tom" -> 86
name == "Jim" -> 77
name == "Jack" -> 95
name == "Lily" -> 100
else -> 0
}
复制代码
可以看到,这种用法是将判断的表达式完整地写在when的结构体当中。注意,Kotlin中判断字符串或对象是否相等可以直接使用==关键字,而不用像Java那样调用equals()方法。可能你会觉得这种无参数的when语句写起来比较冗余,但有些场景必须使用这种写法才能实现。举个例子,假设所有名字以Tom开头的人,他的分数都是86分,这种场景如果用带参数的when语句来写就无法实现,而使用不带参数的when语句就可以这样写:
fun getScore(name: String) = when {
name.startsWith("Tom") -> 86
name == "Jim" -> 77
name == "Jack" -> 95
name == "Lily" -> 100
else -> 0
}
复制代码
现在不管你传入的名字是Tom还是Tommy,只要是以Tom开头的名字,他的分数就是86分。
通过这一小节的学习,相信你也发现了,Kotlin中的when语句相比于Java中的switch语句要灵活很多,希望你能多写多练,并熟练掌握它的用法。
3.循环语句
学习完了条件语句之后,接下来我们开始学习Kotlin中的循环语句。
熟悉Java的人应该都知道,Java中主要有两种循环语句:while循环和for循环。而Kotlin也提供了while循环和for循环,其中while循环不管是在语法还是使用技巧上都和Java中的while循环没有任何区别,因此我们就直接跳过不进行讲解了。如果你没有学过Java也没有关系,只要你学过C、C++ 或其他任何主流的编程语言,它们的while循环用法基本是相同的。
下面我们开始学习Kotlin中的for循环。
Kotlin在for循环方面做了很大幅度的修改,Java中最常用的for-i循环在Kotlin中直接被舍弃了,而Java中另一种for-each循环则被Kotlin进行了大幅度的加强,变成了for-in循环,所以我们只需要学习for-in循环的用法就可以了。
在开始学习for-in循环之前,还得先向你普及一个区间的概念,因为这也是Java中没有的东西。我们可以使用如下Kotlin代码来表示一个区间(从0到10,貌似默认是整数型的):
val range = 0..10
复制代码
这种语法结构看上去挺奇怪的吧?但在Kotlin中,它是完全合法的。上述代码表示创建了一个0到10的区间,并且两端都是闭区间,这意味着0到10这两个端点都是包含在区间中的,用数学的方式表达出来就是[0, 10]。
其中,..是创建两端闭区间的关键字,在..的两边指定区间的左右端点就可以创建一个区间
了。
有了区间之后,我们就可以通过for-in循环来遍历这个区间,比如在main()函数中编写如下代码(运行结果见图1):
fun main() {
for (i in -4..3) {
println(i)
}
}
复制代码
但是在很多情况下,双端闭区间却不如单端闭区间好用。为什么这么说呢?相信你一定知道数组的下标都是从0开始的,一个长度为10的数组,它的下标区间范围是0到9,因此左闭右开的区间在程序设计当中更加常用。Kotlin中可以使用until关键字来创建一个左闭右开的区间,如下所示:
val range = 0 until 10
复制代码
上述代码表示创建了一个0到10的左闭右开区间,它的数学表达方式是[0, 10)。修改main()函
数中的代码,使用until替代..关键字,你就会发现最后一行10不会再打印出来了。
默认情况下,for-in循环每次执行循环时会在区间范围内递增1,相当于Java for-i循环中i++的效果,而如果你想跳过其中的一些元素,可以使用step关键字:
fun main() {
for (i in -6 until 10 step 2) {
print(" "+i)
}
}
复制代码
上述代码表示在遍历[0, 10)这个区间的时候,每次执行循环都会在区间范围内递增2,相当于
for-i循环中i = i + 2的效果。现在重新运行一下代码,结果如下图1所示。
可以看到,现在区间中所有奇数的元素都被跳过了。结合step关键字,我们就能够实现一些更加复杂的循环逻辑。
不过,前面我们所学习的..和until关键字都要求区间的左端必须小于等于区间的右端,也就是这两种关键字创建的都是一个升序的区间。如果你想创建一个降序的区间,可以使用downTo关键字,用法如下:
fun main() {
for (i in 10 downTo 1) {
print(" "+i)
}
}
复制代码
这里我们创建了一个[10, 1]的降序区间,现在重新运行一下代码,运行结果如下图1:
另外,降序区间也是可以结合step关键字跳过区间中的一些元素的,这里我就不进行演示了,你可以自己动手试一试。
for-in循环除了可以对区间进行遍历之外,还可以用于遍历数组和集合,关于集合这部分内容,我们在本章后面的部分就会学到,到时候再延伸for-in循环的相关用法。
如果让我总结一下的话,我觉得for-in循环并没有传统的for-i循环那样灵活,但是却比for-i循环要简单好用得多,而且足够覆盖大部分的使用场景。如果有一些特殊场景使用for-in循环无法实现的话,我们还可以改用while循环的方式来进行实现。
更多关于循环控制的细节可以看 菜鸟教程的循环控制
关于逻辑的控制的部分就先说这几个,之后在做项目训练的过程中也可以不断地学到新的东西