集合
与大多数语言不同,Kotlin区分可变集合和不可变集合,精确控制集合可编辑的时机,有助于消除bug和设计良好的api。
不可变集合和Java中的类似,而可变集合的类名多了Mutable,例如MutableList。
toList扩展方法将复制一个永远不会变的列表项。还有众多更加方便的方法等待你发现。
区间
区间表达式由具有操作符形式的..的rangeTo函数,以及in和!in形成.
if
(i
in
1.
.10
) {
// 等同于 1 <= i && i <= 10
println(i)
}
整形区间(IntRange, LongRange, CharRange)有一个额外的特性:迭代。编译器会将它转换成基于索引的for循环而没有额外开销。
for
(i
in
1.
.4
) print(i)
// 输出“1234”
for
(i
in
4.
.1
) print(i)
// 什么都不输出
for
(i
in
4
downTo
1
) print(i)
// 输出“4321”
for
(i
in
1..4.reversed()
) print(i)
// 输出“4321”
for
(i
in
1.
.4
step
2
) print(i)
// 输出“13”
for
(i
in
1 until 4
) print(i)
// 输出“123”
类型的检查与转换
使用 is 和 !is 操作符来判断类型是否匹配。
在许多情况下,Kotlin不需要显示地使用转换符,编译器会聪明的帮你判断并且转换。
if
(x !
is
String)
return
print(x.length)
// x 自动转换为字符串
如果转换是不可能的,我们就需要显示地进行转换,使用 as 操作符
val
x
: String = y
as
String
如果你想把null转换成String,会出现异常,因为String不是可空的。
val
x
: String? = y
as
String?
当然你还可以这么写。
val
x
: String? = y
as
? String
This表达式
类似Java中,我们在Kotlin也适用this表达式来表示当前的接受者。
在类的成员中,this表示该类的当前对象。
在扩展函数或者带接受者的函数字面值中,this表示点左侧传递的接受者参数。
默认this是指最内层包含它的作用域,如果要引用其他作用域的this,需要使用@label标签限定符。
相等性
引用相等,使用===或者!==操作符,a === b当且仅当a和b指向同一个对象时为true
结构相等,使用==或者!=操作符,a == b相当于a?.equals(b) ?: (b === null),如果a不是null则调用equal函数,否则检查b是否与null引用相等。
空安全
Kotlin的类型系统打着消灭空指针异常的美丽旗子吸引到我。如果Kotlin出现了NPE的唯一可能原因是:
- 显示抛出NPE
- 使用!!操作符
- 外部Java代码导致
- 对于初始化的操作不当,比如为初始化的this用在构造函数的某个地方
在Kotlin中,类型系统区分一个引用可以容纳null还是不能。比如String类型的常规变量不可null,这些在开发时候,AS都会进行提示:
var
a
: String =
"abc"
a =
null
// 编译错误
如果一定要赋null值,可以写作String?
var
b
: String? =
"abc"
b =
null
// ok
这个时候你调用a变量的任何方法或者属性,都不会有NPE,然而b变量却是不安全的,编译器会报错。
如果你要想方设法调用b的方法或者属性,这里提供几个方法
1、通过条件检查null,一如Java的写法。
2、使用Kotlin的语法,你可以这么调用:b?.length。如果b非空就会返回b.length,否则返回null。这种调用简直就是x.y.z的福音啊。原先我们有个类,是记录声音详情页,它有个子类是评论,评论有个属性是评论时间。在Java中如果直接写,detail.comment.time,简直是分分钟可能NPE,BUT,在Kotlin中detail?.comment?.time,我们就无须担心空指针。
3、!!操作符。你可以b!!.length这么写,编译器不会报错。而且如果你需要NPE的话,你只能这么写,当b是null是,就会抛出异常。
Elvis操作符
val
l
:
Int
=
if
(b !=
null
) b.length
else
-1
等价于
val
l
= b?.length ?:
-1
如果?:左侧表达式非空,返回左侧表达式,否则返回右侧。
请注意,throw和return在Kotlin中都是表达式,所以也可以写在Elvis操作符两侧。
异常
Kotlin中所有异常类都是Throwable类的子孙类。使用throw抛出异常,try-catch-finally捕获处理异常。并且try是一个表达式,可以有返回值。
Kotlin没有受检的异常。
类型别名
我们通过类型别名,可以在替代不好听,太长或者任何你嫌弃的类名,而不引入新类型。使用新的别名,等效于原先的类。
typealias
PSI = PlayingSoundInfo