Kotlin学习笔记五、控制语句

一、条件分支

a、简单分支

最简单的条件分支莫过于if…else…

var mod = System.currentTimeMillis() % 3
if (mod == 0L){
	println("if...else...语句下时间节点刚好是可以被2整除的偶数:$mod")
}else if (mod == 1L){
	println("if...else...语句下嗯,这是个技术:$mod")
}else{
	println("if...else...语句下*****也是一个技术和体力兼备的活儿,你以为就是简单的活塞运动?")
}
b、多路分支

kotlin的多路分支其实就是Java里面的switch分支的变种,不过kotlin不再使用switch了,相比Java有许多变化:

  1. 使用when()语句来代替switch().

  2. “case常量值:”则被新的语句“常量值->”所代替。

  3. 然后他没有break结束语,kotlin的机制是默认处理完一个分支就直接跳出多路分支语句。

  4. default关键字被else所代替,而且也是必不可缺的。

    var mod = System.currentTimeMillis() % 3
    when (mod){
    	0L -> println("when语句下时间节点刚好是可以被2整除的偶数:$mod")
    	1L ->  println("when语句下嗯,这是个技术:$mod")
    	else -> println("when语句下****也是一个技术和体力兼备的活儿,你以为就是简单的活塞运动?")
    }
    

我们在Java的switch语句中,经常会出现这样的情况:多个case条件下的处理逻辑是一样的,但是这时候有多少个这样的条件,我们就需要写多少行case语句,然后省去break,这样看着别扭。在kotlin里面,则完全不需要这样麻烦,我们可以将这样的多个条件并排的写在一行,之间用”,”隔开即可。如果这几个条件值刚好又是连续的数字,则我们可以用关键字”in 开始值…结束值”指定区间范围。另外,若条件不在某个连续的区间范围内,我们可以用关键字”!in 开始值…结束值” 指定区间范围。

var inin = (System.currentTimeMillis() % 9).toInt()
when(inin){
	0,1,8,9 -> println("when多条件下,时间多个相同逻辑的条件:$inin")
	in 2..5 -> println("when多条件下,嗯,这是个技术:$mod")
	!in 6..8 -> println("when多条件下,****也是一个技术和体力兼备的活儿,不是简单的活塞运动:$mod")
	else -> println("多条件下的这个lese状态下懒得找什么语句了,凑合吧")
}

这里要注意的是:

开始值.结束值之间的小数点是两个,不是三个,这点要切记
开始值.结束值之间的小数点是两个,不是三个,这点要切记
开始值.结束值之间的小数点是两个,不是三个,这点要切记

重要的事情说三遍。

c、类型判断

就是Java里面的变量属于那种数据类型的判断。Java中用到的关键字是instanceof,而kotlin里面用到的关键字则是is。而且,when()语句判断也可广泛用于类型判断,二者结合,相当奇妙:

var mod = (System.currentTimeMillis() % 3).toInt()
var type = when(mod){
	0 -> mod.toFloat()
	1 -> mod.toDouble()
	else -> mod.toLong()
}
when(type) {
	is Float -> println("Float诗鬼李贺")
	is Double -> println("Double诗仙李白")
	is Long -> println("Long诗圣杜甫")
}

二、循环

a、循环

kotlin的循环主要是for循环和while循环两种,但是for循环有些变化,不再是for(初始值;结束条件;变量变化),而是for(item in …)。比如:

var ancientPoetry:MutableList = mutableListOf(
"天下风云出我辈", "一入江湖岁月催", "皇图霸业谈笑中", "不胜人生一场醉",
"提剑跨骑挥鬼雨", "白骨如山鸟惊飞", "尘事如潮人如水", "只叹江湖几人回",
"英雄路远掌声近", "莫问苍生问星辰", "天地有涯风有信", "大海无量不见人")
var Poetry = ""

for循环实现

for (index in ancientPoetry.indices){
	if ((index + 1) %2 == 0){
	    Poetry = "$Poetry${ancientPoetry.get(index)}。\n"
	}else{
	    Poetry = "$Poetry${ancientPoetry.get(index)}, "
	}
}
logging(Poetry)

while循环实现

var poetryWhile = "";
var index = 0;
while (index < ancientPoetry.size){
	if ((index + 1) % 2 == 0){
	    poetryWhile = "$poetryWhile${ancientPoetry.get(index)}。\n"
	}else{
	    poetryWhile = "$poetryWhile${ancientPoetry.get(index)}, "
	}
	index++
}
logging(poetryWhile)

do…while循环实现:

fun mPoetry(){
    var ancientPoetry:MutableList = mutableListOf(
            "天下风云出我辈", "一入江湖岁月催", "皇图霸业谈笑中", "不胜人生一场醉",
            "提剑跨骑挥鬼雨", "白骨如山鸟惊飞", "尘事如潮人如水", "只叹江湖几人回",
            "英雄路远掌声近", "莫问苍生问星辰", "天地有涯风有信", "大海无量不见人")
    var Poetry = ""
    var index = 0
    var size = ancientPoetry.size - 1
    do {
        if ((index + 1) %2 == 0){
            Poetry = "$Poetry${ancientPoetry.get(index)}。\n"
        }else{
            Poetry = "$Poetry${ancientPoetry.get(index)}, "
        }
        index++
    }while (index <= size)
    	println(Poetry)
}
b、跳出多重循环

当循环中,满足了我们的指定条件或者避免某种异常出现,我们需要在某种情况下跳出循环或者终止循环。

同样的,kotlin里面,对于单层循环,跳出当前循环用的也是continue这个关键字。终止循环用beak这个关键字。

对于多重循环,也可以像Java那样,通过设立标记位来跳出循环或者终止循环。但是kotlin比你想象的要强大。他采取了新的手段,来跳出或者终止多重循环——outside关键字:

var position = 0
outside@ while (position < ancientPoetry.size){
	if (ancientPoetry.get(position).isNullOrBlank()){
	    continue
	}
	var item = ancientPoetry.get(position)
	var local = 0;
	while (local < item.length){
	    var str:String = item[local].toString()
	    if ("回".equals(str)){
			logging(str + "--------------------")
			break@outside
	    }
	    local++
	}
	position++
}

注意上面双层while循环中outside关键字出现的次数和位置。

三、空安全

a、字符串的空判断

开发中让我们最抓狂的莫过于各种防不胜防的异常处理,包括空指针异常NullPointException、数组越界异常IndexOutOfBoundsException、数据类型转换异常ClassCastException/ NumberFormatException等等。特别是空指针异常NullPointException让人焦头烂额,kotlin中常用的校验字符串为空的有以下几个方法:

1、isNullOrempty():为空指针、字符串长度为0时返回true,非空串与可空串均可调用;
2、isNullOrBlank():为空指针,字符串长度为0,全部为空格时返回true,非空串与可空串均可调用;
3、isEmpty():字符串长度为0,只有非空串可调用;
4、isNotEmpty():字符串长度大于0时返回true,只有非空串可以调用;
5、isBlank():字符串长度为0、全部为空格时返回true,只有非空串可调用;
6、isNotBlank():字符串长度大于0且不是全空格串时返回true,只有非空串可调用;

b、声明可空变量

声明一个可空变量就相当于Java里面创建一个对象,但是不通过关键字new去完成初始化:

StringBuffer sb;
或者
StringBuffer sb = null;

这样单纯的声明变量但是没有完成初始化直接使用,那么就很容易引发NullPointException空指针异常。在kotlin里面,则可以避免这种情况出现——声明一个可空变量:

var strCanNull:String?

就这样,就完成了一个可空字符串变量的声明。举例说明:

var str01:String = "我是有值的"
var str02:String? = null
var str03:String? = "可空的字符串"
var length01 = str01.length

// 带“?”方式声明的的变量,使用的时候需要注意在该变量后面带上“? ”标识,否则开发环境会爆红,无法通过IDE编译
var length02 = str02?.length
var length03 = str03?.length
logging("str01字符串的长度:$length01, str02字符串的长度:$length02,str03字符串的长度:$length03")
logging("空字符串用于比较:${str02.equals("22")}")
logging("空字符串用于字符串拼接:${str02 + "我的晓晓"}")

// 空字符串用于截取操作str02.substring(0,2)的时候,开发环境会爆红,提示你进行非空判断。
if (str02 != null) {
	logging("空字符串用于截取:${str02.substring(0,2)}")
}

//因为str01定义的时候就已经确定了他不会是空的,所以使用的时候不用判断,也不用加?标识符
logging("空字符串用于截取:${str01.substring(0,2)}")

str01 = null.toString()

// 经过下面的这几轮测试,我们发现,str01经null.toString()操作后,str01实际上是一个"null"这样的字符串,
// 而且kotlin里面,经过非空赋值操作后,字符串型变量就不再允许进行null的赋值,比如如下操作都是不允许的: 
str01=null/str01:String? = null。

//但可以进行str01=""操作,然后引发未知异常,这一点需要特别注意
logging("str01变为null.toString的结果是啥:$str01")
logging("str01变为null.toString后是个空字符串还是空对象str01==null:${str01==null}")
logging("str01变为null.toString后是个空字符串str01==\"null\":${str01=="null"}")
logging("str01变为null.toString后是个空字符串str01.equals(\"null\"):${str01.equals("null")}")

//虽然不可以进行null的赋值操作,但是可以进行""的赋值操作,然后引发未知异常,这一点需要特别注意。
str01 = ""
try {
	logging("str01字符串进行截取操作:${str01.substring(0,1)}")
}catch (e:Exception){
	logging("对str01=\"\"字符串进行截取操作抛出异常")
	e.printStackTrace()		
}

总结,kotlin引入了空安全的概念,并在编译的实话开始对变量是否为空的校验,相关的操作符说明如下:

1、声明变量实例时,在类名称后面加?,表示该变量可以为空;
2、调用变量方法时,在变量名称后面加?,表示一旦变量为空就返回null;
3、新引入运算符“?:”,表示一旦变量为空,就返回该运算符右边的表达式,类似Java的三目运算,条件为false的时候,就执行”:”右边的表达式;
4、引入新运算符“!!”,通知编译器不做非空校验。如果运行时发现变量为空,就抛出异常。

四、等式判断(字符串相等判断)

简单来说就是判断两个变量的值是否相同或者相等,基本数据类型为相等,引用数据类型为相同。在C语言里面,判断是否相等,用的是“= =”运算符,判断是否相同用的是“strcmp”运算符,C++、Java里面判断是否相等,用的也是“==”运算符,判断是否相同用的是“equels”运算符,但是equels运算符的内部实现其实跟strcmp是一回事,属于换汤不换药的性质。

Kotlin在总结前面语言的一些弊病之后,决心割除这些沿袭已久的积弊,反正都把字符串当做基本数据类型那样,何不直接统一相关的比较运算操作符呢。因此既然基本数据类型直接的比较实用“= =”,那么字符串也用“= =”来判断,相等用“==”,不等用“!=”.

Kotlin学习笔记五、控制语句_第1张图片

var str01 = "asdfgh"
var str02 = "asdfgh"
var str03 = "asdfghjkl"
logging("str01和str02相等吗:${str01==str02}") //相等
logging("str01和str02不相等吗:${str01!=str02}") //相等
logging("str01和str03相等吗:${str01==str03}") //不等

五、引用相等(比如对象)

判断是否相等,有时候仅仅判断两个变量值是否相等还不足以完成某种一致性的判断。要完成这种一致性的判断需要另外一种由内而外全部先更的判断准则,该准则叫做引用相等,意思是除了值相等以外,还要求引用的内存地址也必须相等。

Kotlin里面,结构相等的运算符用的是双等号“= =”;相应的,引用相等用的便是三个等号"= = =",不相等则是“!= =”。
关于几个“=”操作符的含义,可以这样理解:
“=”:赋值运算;
“= =”:等于运算或者比较运算,比较的是对象内部的值,而不是对象本身。重在“结构相等”。
“= = =”:完全等于运算,不仅仅要比较值(结构相等),还要比较对象本身(引用相等),只有二者同时相等,才算是相等,才返回true。

下面列举几个常见的等是判断情景:

1、对于基本数据类型,包括整型、浮点型、单精度、双精度、布尔值、长整型、字符串,结构相等和引用相等没有区别。
2、同一个类声明的不同变量,只要有一个属性不相等,那么既是结构不相等,也是引用不相等。
3、同一个类声明的不同变量,若是equals方法校验的每隔属性都相等,则其结构相等,但是引用不等
4、总的来说,可以这样理解:结构是否相等判断偏重于其内容,引用相等判断偏重于其内存地址。

logging("结构相等判断:str01和str02相等吗:${str01===str02}")//相等
var date:Date = Date()
var dateClone = date.clone()
logging("结构相等判断:date==dateClone吗:${date==dateClone}")//相等
logging("引用相等判断:date===dateClone吗:${date===dateClone}")//不等

六、is操作符和in操作符:

A、运算符is和!is

主要用于判断变量是否属于某种类型,作用跟Java里面的instanceof作用相同,但相比Java关键字,kotlin的关键字及写法更简洁。

Kotlin学习笔记五、控制语句_第2张图片
var listString:List = listOf(“华为”, “小米”, “Apple”, “ViVo”, “OPPO”)
var item = “华为”
logging(“通过is关键字能够判断item这个变量是不是String类型的变量:${item is String}”)

B、运算符 in和!in

Kotlin语言里面的in运算符主要用于判断数组、队列、集合、映射等里面是否包含某个元素。如果我们是在Java里面判断数组或者集合里面是否包含某个元素,只能通过循环的方式拿到每一个item,然后和目标元素对比。这样太耗费资源和时间了。但这在kotlin里面就是一行代码一个关键字的事儿:

logging("通过in关键字能够判断一个list里面是否包含某个元素\"${item}\"么:${item in listString}")

注意最后的{}大括号里面的代码:item in listString,它是关键。

你可能感兴趣的:(Kotlin笔记)