Kotlin专题「四」:逻辑控制语句(if、for、when、while、return、break、continue)

前言: 有些路看起来很近,可是走下去却很远,缺少耐心的人永远走不到尽头。人生,一半是现实,一般是梦想。

一、概述

  前面几篇文章中讲解了 Kotlin 的常量、变量、数据类型和作用域函数等,与 Java 相比还是有一定的区别。这里给大家介绍 Kotlin 的相关逻辑控制语句,如:ifforwhenwhile等。Kotlin 中没有 Java 中的三元运算符,但是用if语句可以实现类似效果;when语句替代了 Java 中的 switch语句;for循环语句废除了 Java 中的(初始值;条件;增减步长)规则,新增了其他规则。下面我们来详细分析:

二、if语句

  Kotlin 中的if语句与 Java 中的语句有一定区别的,它在 Kotlin 中更灵活,除了能实现 Java 中的写法外,还可以实现表达式以及一个块的运用。一个if语句包含一个布尔表达式(类似三目运算符)和一条或多条语句。

(1)传统用法

Kotlin 中的if语句的传统用法与 Java 中的用法一样,没什么好说的,看代码:

    val numA = 0
    val numB = 5
    var result = 10

    if (numA == 5) result = numA

    if (numA > numB) {
        result = numA
    } else {
        result = numB
    }

(2)表达式(三元运算符)

Kotlin 中其实不存在 Java 中的三元运算符条件表达式 ? 表达式1 : 表达式2,因为 Kotlin 中的if语句的表达式会返回一个值,所以不需要三元运算符。

	//Java 的三目运算符   Kotlin中这样写会报错
	//int result = numA > numB ? 10 : 20;
	
	//kotlin 中直接使用 if…else…替代
	 var result = if (numA > numB) {
        10
    } else {
        20
    }
    Log.e(TAG, "if语句:result == $result")
    
	//当numA>numB时,result=10,否则result=20
    //简写为
	var result = if (numA > numB) 10 else 20

打印数据如下:

if语句:result == 20

可以看到在 Kotlin 中if语句可以作为一个表达式并且返回一个值。

三、for语句

Kotlin for循环可以对任何提供迭代器(iterator)的对象进行遍历。循环数组会被编译为一个基于索引index的循环,不会创建迭代器对象。for循环语句废除了 Java 中的(初始值;条件;增减步长)规则,新增了其他规则。其语法如下:

for (item in collection){
	print(item)
{
  • in:    运算符,表示在…之内的意思,使用in操作符来遍历。

3.1 递增(..until

..until都是表示递增的区间,只是区间的取值范围不同。

  • ..:    创建从此值到指定值的范围。表示一个区间,该区间是闭区间,包括开始值和结束值,[n,m]。
  • until:  创建从此值但不包括指定的值的范围。表示一个区间,该区间是半闭区间,包括开始值,不包括结束值,[n,m)。
	//java 的for循环递增
//    for (int i = 0; i < 5; i++) {
//        System.out.println(i);
//    }
	
    //循环5次,步长为1的递增
    for (i in 1..5) {//1   2   3	4	 5
        print("$i \t")
    }

    //循环4次,步长为1的递增
    for (i in 1 until 5) {//1	2	3	4
        print("$i \t")
    }

打印数据如下:

for语句:..递增 == 1  2	 3	 4	 5

for语句:until递增 == 1	 2	 3	 4

注意:区间是从小到大的,如果开始的数值比最后的还要大则没有意义。在until中,如果[to]值,即最后的数值,这里为5,小于或等于当前值i,则返回的数值为空。

3.2 递减downTo

Kotlin 使用downTo表示递减。

  • downTo:  通过步长-1返回从该值向下到指定的值的序列。表示一个区间,该区间是闭区间,包括开始值和结束值,[n,m]。
	//循环5次,步长为-1的递减
    for (i in 5 downTo 1) {
        print("$i \t")
    }

上面的区间是5 downTo 1,当前值i必须大于或者等于[to]值,即1,如果当前值i小于[to]值,则返回的数值为空。打印数据如下:

for语句:downTo递减 == 5	  4	  3	  2	  1

3.3 步长step

上面的例子中的步长都是为1,步长我们可以根据自己需求来设置:

  • step:  返回与给定步骤执行相同范围的进程。也就是说取值的间隔是多少。
    //step:步长为2,循环两次的递减
    for (i in 6 downTo 1 step 2) {
        print("$i \t")
    }

打印数据如下:

for语句:step步长为2 == 4  2

3.3 遍历字符串

for循环也能遍历字符串,会把每个字符逐个打印出来。

    //遍历字符串
    for (i in "HelloWord") {
        print("$i \t")
    }

打印数据如下:

for语句:字符串 == H	  e	  l	  l	  o	  W	  o	  r	  d

3.4 遍历集合

for循环遍历集合:

    //遍历集合
    val userArray = arrayListOf(User("姓名1"), User("姓名2"), User("姓名3"))
    for (item in userArray) {
        print("${item.name} \t")
    }

打印数据如下:

for语句:遍历集合 == 姓名1	姓名2	姓名3

3.5 通过索引遍历

如果你想通过索引遍历遍历集合或数组,可以使用indices关键字。

  • indices:  返回此集合的有效索引的[int范围]
    //indices比遍历
    val intArray = arrayListOf(10, 20, 30, 40)
    for (i in intArray.indices) {
        Log.e(TAG, "for语句:indices遍历 == intArray[$i]:${intArray[i]}")
    }

打印数据如下:

for语句:indices遍历 == intArray[0]10
for语句:indices遍历 == intArray[1]20
for语句:indices遍历 == intArray[2]30
for语句:indices遍历 == intArray[3]40

注意:这种“在区间上遍历”会编译成优化的实现而不会创建额外的对象。

3.6 库函数 withIndex

for循环中的withIndex返回一个惰性的[Iterable],它将原始集合的每个元素包装成一个IndexedValue对象,其中包含该元素和元素本身的索引。IndexedValue表示一个在集合或者序列中的值及其在该集合或序列中的索引的数据类型。源码如下:

public data class IndexedValue<out T>(public val index: Int, public val value: T)

来简单使用下:

    //withIndex:包含该元素和元素索引
	val intArray = arrayListOf(10, 20, 30, 40)
    for ((index, value) in intArray.withIndex()) {
        Log.e(TAG, "for语句:withIndex == index: $index, value: $value")
    }

打印数据如下:

for语句:withIndex == index: 0, value: 10
for语句:withIndex == index: 1, value: 20
for语句:withIndex == index: 2, value: 30
for语句:withIndex == index: 3, value: 40

四、when 语句

when将它的参数和所有分支条件比较,直到某个分支满足条件,跳出语句。when既可以当做表达式使用也可以当做语句使用,如果被当做表达式,那么符合条件的分支的值就是整个表达式的值;如果当语句使用则忽略分支的值。when操作符类似 Java 中的 switch 操作符,甚至可以替换if语句。

4.1 普通用法

when操作符用 -> 表示要执行的操作,类似switch,同时每个分支不需要像switch语句那样添加break跳出分支,如果分支下面只有一个语句,则可以省略块符号{},否则需要加上块符号{}将要执行的操作包起来。

	//Java的 switch 语法
	int num = 0;
    switch (num) {
        case 2:
            System.out.print("switch语句:num == 2");
            break;
        case 4:
            System.out.print("switch语句:num == 4");
            break;
        default:
            System.out.print("switch语句:num != 2 && num != 4");
    }

	//Kotlin
    var num = 0
    when (num) {
        2 -> print("when语句:num == 2")
        4 -> {
             print("when语句:num == 4")
        }
        else -> {//注意块, else 等同于java中的 default
            print("when语句:num != 2 && num != 4")
        }
    }

when中,else 的含义等同于 switch 中的 default ,如果其他分支不满足条件都会走else 分支。打印数据如下:

when语句:num != 2 && num != 4

4.2 分支处理方式相同

如果很多分支用相同的方式处理,则可以把多个分支条件放在一起,用,分隔开来,相当于 switch 中不用break跳转的语句:

    var num = 2
    when (num) {
    	//2,4分支相同的方式处理
        2, 4 -> print("when语句:num == 2 or num == 4")
        else -> print("when语句:num != 2 && num != 4")
    }

打印数据如下:

when语句:num == 2 or num == 4

4.3 条件使用任意表达式

when 语句中的条件可以使用任意表达式,并不是只局限于常量,相当于 if 表达式的用法:

    when (num > 0) {
        true -> print("when语句:num > 0")
        false -> print("when语句:num < 0")
    }

打印数据如下:

when语句:num > 0

4.4 检查值是否在集合或者数组中

那么也可以检查一个条件是否在in或者不在!in一个区间或者集合中,in表示在…范围内,!in表示不在…范围内。

    var num = 5
    val intArray = arrayOf(6, 7, 8, 9, 10)
    when (num) {
        in 1..5 -> print("when语句:num == 属于 1 ~ 5 中")
        !in intArray -> print("when语句:num == 不在intArray集合中")
        else -> print("when语句:num == 都不属于")
    }

打印数据如下:

when语句:num == 属于 1 ~ 5

4.5 检查值是否为指定类型的值

检测一个值是is或者不是!is一个特定的类型。注意:kotlin 的智能转换,可以访问该类型的属性和方法而不需要任何的检测。

    fun isWhen(x: Any) = when (x) {
        is Int -> print("when语句:x 是Int类型")
        !is String -> print("when语句:x 不是String类型")
        else -> print("when语句:x 是String类型")
    }
	//调用
	isWhen("山水有相逢")

打印数据如下:

when语句:x 是String类型

4.6 不提供参数

when 也可以用来取代if … else链,如果不提供参数,所有的分支条件都是简单的布尔表达式,而当一个分支条件为true时,则执行该分支,跳出语句。

    var str = "kotlin"
    val strArray = arrayOf("android", "kotlin", "java")
    
    when {
        str is String -> print("when语句:str 是String类型")
        "java" in strArray -> print("when语句:java == 在集合中")
    }

打印数据如下:

when语句:str 是String类型

可以看到in运算符还可以判断集合内是否包含某实例。

五、while与do…while语句

Kotlin 中的whiledo…while语句与 Java 中的用法相同。while语句如果不满足条件是不会进入循环的,不同的是do…while是先执行循环再判断条件,循环至少会执行一次。

while的结构如下:

	while( 布尔表达式 ) {
		//TODO 循环内容
	}

while的结构如下:

	do {
       //TODO 循环内容
	}while(布尔表达式);

do...while 语句的使用:

    var numA = 1
    while (numA < 6) {
        Log.e(TAG, "while语句:循环了$numA 次")
        numA++
    }

打印数据如下:

while语句:循环了1while语句:循环了2while语句:循环了3while语句:循环了4while语句:循环了5

do...while 语句的使用:

    var numB = 0
    do {
        Log.e(TAG, "do...while语句:循环了$numB 次")
        numB--
    } while (numB > 0)

打印数据如下:

do...while语句:循环了1

六、返回和跳转语句(return、break、continue)

Kotlin 有三种结构化跳转:return、break、continue,和 Java 的用法和意义一致。

  • return:   默认从直接包围它的函数或者匿名函数返回;
  • break:    终止最直接包围它的循环;
  • continue:  继续下一次最直接包围它的循环。即跳出本次循环,即系下一次循环。

另外,在 Kotlin 中任何表达式都可以使用标签来标记(label),标签的形式是标签名后接@标识符,如flag@等,标签符由自己决定:

flag@ for (i in 1 .. 10) { 
	{

我们就可以使用一个标签限定一个 brea k或一个 continue,使用标签限定的 break 会跳到刚好位于该标签指定的循环后面的执行点,continue 继续标签指定的循环的下一个迭代。

6.1 break、continue和标签

在 Kotlin 中支持传统的 break 和 continue 操作符:

    //基本用法
    for (i in 1..10) {
        if (i == 4) continue//i == 4时,跳出当前循环,进入下一次循环
        Log.e(TAG, "break和continue:i == $i")
        if (i > 6) break//i > 6时跳出循环
    }

打印数据如下:

breakcontinue:i == 1
breakcontinue:i == 2
breakcontinue:i == 3
breakcontinue:i == 5
breakcontinue:i == 6
breakcontinue:i == 7

现在,我们可以使用一个标签来定义一个 break 或 continue :

    //使用一个标签来定义一个break或continue:
    Log.e(TAG, "=== break和标签一起使用 ===")
    loop1@ for (i in 1..10) {
        for (j in 1..10) {
            if (true) {
                Log.e(TAG, "break: i + j == $i + $j")
                break@loop1//跳出@loop1循环
            }
        }
    }

    Log.e(TAG, "=== continue和标签一起使用 ===")
    loop2@ for (i in 1..10) {
        for (j in 1..10) {
            if (true) {
                Log.e(TAG, "continue: i + j == $i + $j")
                continue@loop2//跳出本次循环,进入下一个@loop2循环
            }
        }
    }

打印数据如下:

=== break和标签一起使用 ===
break: i + j == 1 + 1
=== continue和标签一起使用 ===
continue: i + j == 1 + 1
continue: i + j == 3 + 1
continue: i + j == 4 + 1
continue: i + j == 5 + 1
continue: i + j == 6 + 1
continue: i + j == 7 + 1
continue: i + j == 8 + 1
continue: i + j == 9 + 1
continue: i + j == 10 + 1

可以看到使用一个标签限定一个 break 或一个 continue 后,使用标签限定的 break 会跳到刚好位于该标签指定的循环后面的执行点loop1@,continue 继续标签loop2@指定的循环的下一个迭代。

6.2 return和标签

Kotlin 有函数字面量,局部函数和对象表达式。所以 Kotlin 函数可以被嵌套,标签限制的 return 允许我们从外层函数返回,最重要的一个用途就是从 lambda 表达式中返回。普通使用:

private fun returnGrammar() {
    var intArrays = arrayListOf(1, 2, 3, 4)
    for (item in intArrays) {
        if (item == 2) return
        Log.e(TAG, "return:item == $item")
    }
    Log.e(TAG, "return:外层函数")
}

打印数据如下:

return:item == 1

这个 return 表达式从最直接包围它的函数returnGrammar()中返回,注意,这种非局部的返回只支持传给内联函数的 lambda 表达式,如果我们需要从 lambda 表达式中返回,我们必须加标签并用以限制return。

(1)标签和return一起使用

//1.标签和return一起使用
private fun returnGrammar() {
    var intArrays = arrayListOf(1, 2, 3, 4)
    //数组的迭代器理由有一个Iterable.forEach()方法,传入了一个it参数,为数组中的元素
    intArrays.forEach flag@{
    	if (it == 2) return@flag
    	Log.e(TAG, "return:item == $it")
    }
    Log.e(TAG, "return:外层函数")
}

可以看到,return@flag只会从 lambda 表达式中返回,并未从外层函数中返回,继续执行输出了3,4外层函数。打印数据如下:

return:item == 1
return:item == 3
return:item == 4
return:外层函数

(2)使用隐式标签,该标签与接受该 lambda 的函数同名

 //2.使用隐式标签,该标签与接受该 lambda 的函数同名
private fun returnGrammar() {
    var intArrays = arrayListOf(1, 2, 3, 4)
    intArrays.forEach {
        if (it == 2) return@forEach
        Log.e(TAG, "return:item == $it")
    }
    Log.e(TAG, "return:外层函数")
}

通常使用隐式标签更方便,该标签与接受该 lambda 的函数forEach同名。打印数据如下:

return:item == 1
return:item == 3
return:item == 4
return:外层函数

(3)使用匿名函数代替 lambda 表达式,返回是从匿名函数中返回而不是外层函数

 //3.使用匿名函数代替 lambda 表达式,返回是从匿名函数中返回而不是外层函数
private fun returnGrammar() {
    var intArrays = arrayListOf(1, 2, 3, 4)
    intArrays.forEach(fun(value: Int) {
        if (value == 2) return
        Log.e(TAG, "return:value == $value")
    })
    Log.e(TAG, "return:外层函数")
}

使用一个匿名函数替代 lambda 表达式,匿名函数内部的 return 语句将从该匿名函数自身返回。打印数据如下:

return:value == 1
return:value == 3
return:value == 4
return:外层函数

(4)注意前三个示例中使用的本地return类似于在常规循环中使用的 continue。对于 break 没有直接的等价,但是可以同过添加另一个嵌套 lambda 和非本地 return 来模拟:

private fun returnGrammar() {
    var intArrays = arrayListOf(1, 2, 3, 4)
    run loop@{
        intArrays.forEach {
            if (it == 2) return@loop
            Log.e(TAG, "return:@loop == $it")
        }
    }
    Log.e(TAG, "return:外层函数")
}

打印数据如下:

return@loop == 1
return:外层函数

当要返回一个值的时候,解析器优先选择标签限制的 return:

return@flag 10

意思是从标签@flag处返回10,而不是返回一个标签标注的表达式@flag 10

七、总结

Kotlin语句含义注意事项
if(条件判断)一个if语句包含一个布尔表达式和一条或多条语句。1. if 语句可以作为一个表达式并且返回一个值;
2.能实现 Java 的三目运算符和块级运用。
for(循环)对任何提供迭代器(iterator)的对象进行遍历1.in运算符,表示在…之内的意思,使用 in 操作符来遍历;
2...until都是表示递增的区间,只是区间的取值范围不同;
3.downTo表示递减,step表示设置步长;
4.indices返回集合的有效索引;
5.withIndex返回一个IndexedValue对象包含该元素和元素本身的索引。
when(分支)将它的参数和所有分支条件比较,直到某个分支满足条件,跳出语句1.-> 表示要执行的操作,类似 switch 的;
2.分支下面只有一个语句,则可以省略块符号{};
3.else 的含义等同于 switch 中的default;
4.多个分支有相同方式处理,分支可以用逗号,隔开;
5.条件可以使用任意表达式;
6.如果不提供参数,所有的分支条件都是简单的布尔表达式,为 true 则跳出语句。
while(循环)满足条件则执行下面的逻辑不满足条件是不会进入循环。
do…while(循环)先执行逻辑再判断条件是否满足先执行循环再判断条件,循环至少会执行一次。
return(跳出)默认从直接包围它的函数或者匿名函数返回用法与 Java 类似,可以配合标签使用,如:return@loop。
break(跳出)终止最直接包围它的循环用法与 Java 类似,可以配合标签使用,如:break@loop。
continue(跳出)继续下一次最直接包围它的循环。即跳出本次循环,即系下一次循环用法与 Java 类似,可以配合标签使用,如:continue@loop。

源码地址:https://github.com/FollowExcellence/KotlinDemo-master

点关注,不迷路


好了各位,以上就是这篇文章的全部内容了,能看到这里的人呀,都是人才

我是suming,感谢各位的支持和认可,您的点赞、评论、收藏【一键三连】就是我创作的最大动力,我们下篇文章见!

如果本篇博客有任何错误,请批评指教,不胜感激 !

要想成为一个优秀的安卓开发者,这里有必须要掌握的知识架构,一步一步朝着自己的梦想前进!Keep Moving!

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值