对于如下Java函数,可传递null或者值为null的String
int strLen(String s) {
return s.length();
}
而在Kotlin中,如下函数不能传递null或值为null的String,否则会在编译期报错,保证了永远不会在运行时报空指针异常
fun strLen(s: String) = s.length
如果接收null,需要在类型名称后面加上?标记
fun strLen(s: String?): Int =
if (s != null) s.length else 0
把一次null检查和方法调用合并成一个操作,为空时返回null
fun printAllCaps(s: String?) {
val allCaps: String? = s?.toUpperCase()
println(allCaps)
}
调用结果也是可空的,如下打印ABC、null
println("abc")
println(null)
同上,但为空时返回冒号后面的默认值,如下s为空返回""
fun foo(s: String?) {
val t: String = s ?: ""
}
把值转换成指定的类型,若转换失败则返回null
class Person(val name: String) {
override fun equals(other: Any?): Boolean {
val otherPerson = other as? Person ?: return false
return otherPerson.name == name
}
}
把值转换成非空类型,若为空则抛出异常,堆栈信息只会表明异常发生在哪一行代码,而不是哪一个表达式,应避免在同一行使用多个!!
fun ignoreNulls(s: String?) {
val sNotNull: String = s!!
println(sNotNull.length)
}
当把可空值作为实参传递给非空值的函数时,可使用let
fun sendEmailTo(email: String) {
println("sendEmailTo")
}
let只会在值非空时调用
val email1: String? = "AAA"
email1?.let { sendEmailTo(it) }
val email2: String? = null
email2?.let { sendEmailTo(it) }
如下每次使用myService变量,都需要判空
class MyService {
fun getService(): String = "Service"
}
class Test {
private var myService: MyService? = null
fun setUp() {
myService = MyService()
}
fun action() {
myService?!.getService()
}
}
可使用lateinitb表明变量可以延迟初始化,不用先置为null,省去判空条件
class MyService {
fun getService(): String = "Service"
}
class Test {
private lateinit var myService: MyService
fun setUp() {
myService = MyService()
}
fun action() {
myService.getService()
}
}
String的扩展函数isNullOrBlank()判断当前字符串是否为空或者空白,this可能为null,若不为null,则可以安全调用isBlank()
public inline fun CharSequence?.isNullOrBlank(): Boolean {
return this == null || this.isBlank()
}
Kotlin所有泛型类和泛型函数的类型参数默认都是可空的,如下函数可传递null
fun printHashCode(t: T) {
println(t?.hashCode())
}
要使类型参数非空,必须指定一个非空的上界
fun printHashCode(t: T) {
println(t.hashCode())
}
Java使用@Nullable表示可为空,@NotNull表示非空,当不存在注解时,会作为Kotlin的平台类型(即不知道可空性的类型),由开发者自己处理
Kotlin不会自动转换类型,需要显示调用转换函数
val i = 1
val l: Long = i.toLong()
Any是所有类型的父类,对应于Java的Object
当函数未声明返回值类型时,默认为Unit,对应于Java的void
fun f() {
}
fun fu(): Unit {
}
Unit可以作为泛型的类型参数,而void不行,如下使用Unit作为返回值,不用显示return
interface Processor {
fun process(): T
}
class NoResultProcessor : Processor {
override fun process() {
}
}
Nothing没有任何值,只有被当作函数返回值,或者当作泛型函数返回值的类型参数才有意义
fun fail(msg: String): Nothing {
throw IllegalStateException(msg)
}
需要注意,集合可空性和集合元素可空性是不一样的
fun addValidNumbers(numbers: List) {
var validNumbers = 0
for (number in numbers) {
if (number != null) {
validNumbers += number
}
}
}
可使用库函数优化
fun addValidNumbers(numbers: List) {
var validNumbers = numbers.filterNotNull().sum()
}
Collection中的方法都是读取集合的操作,MutableCollection才包含写集合的操作
fun copyElements(source: Collection, target: MutableCollection) {
for (item in source) {
target.add(item)
}
}
只读集合不一定是不可变的,可能同时有MutableCollection引用它
一种Java集合在Kotlin都有只读和可变两种表示,不能保证传递给Java的集合不会被修改及添加null
val letters = Array(26) { i -> ('a' + i).toString() }
数组的类型参数会被成为对象类型,若要生成基本数据类型的数组,可以使用xxxArray()
val a = IntArray(5)
val b = intArrayOf(0, 1, 2, 3, 4)
val c = IntArray(5) { i -> (i + 1) }
println(a.joinToString(" ")) // 0 0 0 0 0
println(b.joinToString(" ")) //0 1 2 3 4
println(c.joinToString(" ")) //1 2 3 4 5
可对装箱的数组或集合转为基本数据类型的数组
val list = listOf(1, 2, 3)
val array = list.toIntArray()