Kotlin基础——类型系统

?

对于如下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 ?: ""
}

as?

把值转换成指定的类型,若转换失败则返回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

当把可空值作为实参传递给非空值的函数时,可使用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 <T> printHashCode(t: T) {
    println(t?.hashCode())
}

要使类型参数非空,必须指定一个非空的上界

fun <T : Any> printHashCode(t: T) {
    println(t.hashCode())
}

可空性和Java

Java使用@Nullable表示可为空,@NotNull表示非空,当不存在注解时,会作为Kotlin的平台类型(即不知道可空性的类型),由开发者自己处理

基本数据类型

  • Kotlin非空的基本数据类型转换为Java的基本数据类型
  • Kotlin可空的基本数据类型转换为Java的基本数据包装类

数字转换

Kotlin不会自动转换类型,需要显示调用转换函数

val i = 1
val l: Long = i.toLong()

Any、Any?

Any是所有类型的父类,对应于Java的Object

Unit

当函数未声明返回值类型时,默认为Unit,对应于Java的void

fun f() {
    
}

fun fu(): Unit {

}

Unit可以作为泛型的类型参数,而void不行,如下使用Unit作为返回值,不用显示return

interface Processor<T> {
    fun process(): T
}

class NoResultProcessor : Processor<Unit> {
    override fun process() {
        
    }
}

Nothing

Nothing没有任何值,只有被当作函数返回值,或者当作泛型函数返回值的类型参数才有意义

fun fail(msg: String): Nothing {
    throw IllegalStateException(msg)
}

集合

可空性和集合

需要注意,集合可空性和集合元素可空性是不一样的

fun addValidNumbers(numbers: List<Int?>) {
    var validNumbers = 0
    for (number in numbers) {
        if (number != null) {
            validNumbers += number
        }
    }
}

可使用库函数优化

fun addValidNumbers(numbers: List<Int?>) {
    var validNumbers = numbers.filterNotNull().sum()
}

只读集合和可变集合

Collection中的方法都是读取集合的操作,MutableCollection才包含写集合的操作

fun <T> copyElements(source: Collection<T>, target: MutableCollection<T>) {
    for (item in source) {
        target.add(item)
    }
}

只读集合不一定是不可变的,可能同时有MutableCollection引用它

Koltin集合和Java

一种Java集合在Kotlin都有只读和可变两种表示,不能保证传递给Java的集合不会被修改及添加null

在这里插入图片描述

数组

  • arrayOf() 创建包含指定参数的数组
  • arrayOfNulls() 创建可空数组
  • Array() 调用Lambda表达式构建数组元素
val letters = Array<String>(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<Int>(1, 2, 3)
val array = list.toIntArray()

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>