Kotlin实战(四) Kotlin的类型系统

1 可空性

1.1 可空类型
fun strLen1(s: String) = s.length


//Type? = Type or null
fun strLen2(s: String?) {
    //Error:only safe(?.) of non-null asserted(!!.) calls are allowed on a nullable receiver of type kotlin.String?
//    s.length
}

//增加了判空检查,则可以正常编译
fun strLen3(s: String?) = if (s != null) s.length else 0

fun test1() {
    //1 Error:NUll can't be a value of a non-null type String
    //strLen(null)

    //2 在类型后面加上"?"号标记,即可传递任意参数包括null
    strLen2(null)

    //3 不能把值赋给非空变量
    val x: String? = null
    //var y: String = null//Error:NUll can't be a value of a non-null type String
}
1.2 类型的含义
1.3 安全调用运算符: “?.”
fun printAllCaps(s: String?) {
    val allCaps: String? = s?.toUpperCase()
    println(allCaps)
}

//1 使用安全调用处理可空属性
class Employee(val name: String, val manager: Employee?)

fun managerName(employee: Employee): String? = employee.manager?.name

//2 链接多个安全调用
class Address(val streetAddress: String, val zipCode: Int, val city: String, val country: String)

class Company(val name: String, val address: Address?)

class Person(val name: String, val company: Company?)

fun Person.countyName(): String {
    val country = this.company?.address?.country
    return if (country != null) country else "unknow"
}


fun test2() {
    printAllCaps("abc")
    printAllCaps(null)

    val ceo = Employee("Da Boss", null)
    val developer = Employee("Bob smith", ceo)

    println(managerName(developer))
    println(managerName(ceo))

    val person = Person("Dmitry", null)
    println(person.countyName())

}

输出结果

ABC
null
Da Boss
null
unknow
1.4 Elvis运算符: “?:”
fun foo(s: String?) {
    //如果s为空,结果是一个空的字符串
    val t: String = s ?: "empty str"
    println("t = $t")
}

//1 使用Elvis运算符处理null值
fun strLenSafe(s: String?): Int = s?.length ?: 0


//2 同时使用throw和Elvis运算符
fun printShippingLabel(person: Person) {
    val address =
        person.company?.address ?: throw IllegalArgumentException("No address") //如果缺少addre就抛出异常
    with(address) {
        println(streetAddress)
        println("$zipCode $city, $country")
    }

}

fun test3() {
    foo(null)
    val value = strLenSafe(null)
    println("value = $value")

    val address = Address("Elsestr.47", 80687, "Munich", "Germany")
    val jetbrains = Company("JetBrains", address)
    val person = Person("Dmitry", jetbrains)

    printShippingLabel(person)

    printShippingLabel(Person("Alexey", null))
}

输出结果

t = empty str
value = 0
Elsestr.47
80687 Munich, Germany
Exception in thread "main" java.lang.IllegalArgumentException: No address
1.5 安全转换: “as?”
//1 使用安全转换实现equals
class Person2(val firstName: String, val lastName: String) {
    override fun equals(other: Any?): Boolean {
        val otherPerson = other as? Person2 ?: return false

        return otherPerson.firstName == firstName && otherPerson.lastName == lastName
    }

    override fun hashCode(): Int {
        return firstName.hashCode() * 37 + lastName.hashCode()
    }
}

fun test4() {
    var p1 = Person2("Dmitry", "Jemerov")
    var p2 = Person2("Dmitry", "Jemerov")

    println(p1.equals(p2))

    println(p1.equals(42))
}
true
false
1.6 非空断言:“!!”
fun ignoreNulls(s: String?) {
    val sNotNull: String = s!!
    println(sNotNull.length)
}

fun test5() {
    ignoreNulls(null)
}
Exception in thread "main" kotlin.KotlinNullPointerException
1.7 “let”函数
//1 使用let调用一个接受非空参数的函数
fun sendEmailTo(email: String) {
    println("Sending email To $email")
}

fun test6() {
    var email: String? = "yole@example.com"
    email?.let { sendEmailTo(it) }

    email = null
    email?.let { sendEmailTo(it) }
}
1.8 延迟初始化的属性
//1 使用非空断言访问可空属性
class MyService {
    fun performAction(): String = "Foo"
}
1.9 可空类型的拓展
//1 用可空接受者调用扩展函数
fun verifyUserInput(input: String?) {
    if (input.isNullOrBlank()) {
        println("please fill in the required fields")
    }
}

fun test7() {
    verifyUserInput("")
    verifyUserInput(null)
}

输出结果

please fill in the required fields
please fill in the required fields
1.10 类型参数的可空性
//1 处理可空的类型参数
// <T> ----> <Any?>
fun <T> printHasCode1(t: T) {
    //因为"t"可能为null, 所以必须用安全调用
    println(t?.hashCode())
}

//2 为类型参数声明为空上界
fun <T : Any> printHasCode2(t: T) {
    println(t.hashCode())
}

fun test8() {
    printHasCode1(null)
//    printHasCode2(null)//无法编译,不能传递null
}

输出结果

null
1.11 可空性和java
//2 不使用null检查访问java类
fun yellAt(person: PersonB) {
    println(person.name.toUpperCase() + "!!!")
}

//3 使用null检查来访问java类
fun yellAtSafe(person: PersonB) {
    //这种情况下,kotlin完全不知道String类型的可空性
    println((person.name ?: "Anyone").toUpperCase() + "!!!")
}

//3 kotlin重写java方法时,可以选择把参数和返回值定义成可空的,也可以定义成非空的
class KotlinClass1 : JavaInterface {
    override fun javaMethod(param: String?) {

    }
}

class KotlinClass2 : JavaInterface {
    override fun javaMethod(param: String) {

    }
}


fun test9() {
    yellAtSafe(PersonB(null))
    yellAt(PersonB(null))
}

输出结果

ANYONE!!!
Exception in thread "main" java.lang.IllegalStateException: person.name must not be null

2 基本数据类型和其他基本类型

2.1 基本数据类型:Int,Boolean及其他
//kotlin不区分基本类型和包装类型
fun test10() {
    val i: Int = 1
    val list: List<Int> = listOf(1, 2, 3)
}

//整数类型    --->  Byte, Short, Int, Long
//浮点数类型  ---> Float, Double
//字符类型    ---> Char
//布尔类型    ---> Boolean
2.2 可空的基本数据类型:Int?,Boolean?及其他
data class PersonA(val name: String, val age: Int? = null) {
    fun isOlderThan(other: PersonA): Boolean? {
        if (age == null || other.age == null) {
            return null
        }

        return age > other.age
    }
}

fun test11() {
    println(PersonA("zhangsan", 35).isOlderThan(PersonA("Amy", 42)))
    println(PersonA("zhangsan", 35).isOlderThan(PersonA("Amy")))
}

输出结果

false
null
2.3 数字转换
fun foo(l: Long) = println(l)

fun test12() {
    val i = 1

    //Error:类型不匹配
//    val l:Long = i

    //必须显式的进行转换
    val l: Long = i.toLong()
    /*-------------------------------*/

    val x = 1
    val list = listOf(1L, 2L, 3L)
    //x in list//不编译,必须显式的转换类型

    println(x.toLong() in list)
    /*-------------------------------*/
    val b: Byte = 1  //常量有正确的类型
    val c = b + 1L //可以进行字节类型和长整型参数的计算
    foo(42) //编译器认为42是一个长整形
}
2.4 “Any”和“Any?”:根类型
fun test13() {
    // Any类型是kotlin所有非空类型的超类型 包括Int等基本类型
    val answer: Any = 42
    // Any是非空类型 Any?则包含null类型
}
2.5 Uint类型:Kotlin的“void”
//1 在Kotlin中Unit类型和Java中的void一样
fun f1(): Unit {}

fun f2() {}

//2 不同点:可以作为泛型参数返回
interface Processor<T> {
    fun process(): T
}

class NoResultProcessor : Processor<Unit> {
    override fun process() {
        //这里不需要显示的return
    }

}
2.6 Nothing类型:“这个函数永不反回”
//不会正常终止的函数使用Nothing类型作为返回类型
fun fail(message: String): Nothing {
    throw IllegalStateException(message)
}

3 集合与数组

3.1 可空性和集合
//要小心决定什么是可空的:集合的元素还是集合本身   List<Int?>   List<Int>?
//1 创建一个包含可空值的集合
fun readNumbers(reader: BufferedReader): List<Int?> {
    //创建包含可空Int值的列表
    val result = ArrayList<Int?>()
    for (line in reader.lineSequence()) {
        try {
            val number = line.toInt()
            //向列表添加整数
            result.add(number)
        } catch (e: NumberFormatException) {
            result.add(null)
        }
    }

    return result
}

//2 使用可空值的集合
fun addValidNumbers1(numbers: List<Int?>) {
    var sumOfValidNumbers = 0
    var invalidNumbers = 0
    for (number in numbers) {
        if (number != null) {
            sumOfValidNumbers += number
        } else {
            invalidNumbers++
        }
    }
    println("Sum of valid numbers: $sumOfValidNumbers")
    println("Invalid numbers: $invalidNumbers")
}

//3 对包含可空指的集合使用filterNotNull
fun addValidNumbers2(numbers: List<Int?>) {
    val validNumbers = numbers.filterNotNull()
    println("Sum of valid numbers:${validNumbers.sum()}")
    println("Invalid numbers:${numbers.size - validNumbers.size}")
}
3.2 只读集合与可变集合
//1 使用只读集合接口与可变集合接口
fun <T> copyElements(source: Collection<T>, target: MutableCollection<T>) {
    for (item in source) {
        target.add(item)
    }
}

fun test14() {

    //1 向可变集合target集合中添加元素
    val source: Collection<Int> = arrayListOf(3, 5, 7)
    val target: MutableCollection<Int> = arrayListOf(1)
    copyElements(source, target)
    println(target)

    //2 不能把只读集合类型的变量作为target参数传给函数,即便它的值是一个可变集合
//    copyElements(target, source) //Error:Type mismatch
}

输出结果

[1, 3, 5, 7]
3.3 kotlin集合和java
fun printlnUppercase(list: List<String>) {
    println(CollectionUtils.uppercaseAll(list))
    println(list.first())
}

fun test15() {
    val list = listOf("a", "b", "c")
    printlnUppercase(list)
}

输出结果

[A, B, C]
A
3.4 作为平台类型的集合
//定义在java中的接口,在kotlin中实现时,编译器允许kotlin代码可空或者非空
//1 FileContentProcessor的kotlin实现
class FileIndexer : FileContentProcessor {
    override fun processContents(
        path: File?,
        binaryContents: ByteArray?,
        textContents: MutableList<String>?
    ) {

    }
}
3.5 对象和基本数据类型的数组
fun test16(args: Array<String>) {
    //1 使用数组
    for (i in args.indices) {
        println("Argument $i is ${args[i]}")
    }

    //2 创建字符数组
    val letters = Array<String>(26) { i -> ("a$i").toString() }
    println(letters.joinToString(""))

    //3 想vararg方法传递集合
    val strings = listOf("a", "b", "c")
    println("%s/%s/%s".format(*strings.toTypedArray()))

    //4 对数组使用forEachIndexed
    args.forEachIndexed { index, element ->
        println("Argument $index is $element")
    }
}

fun test16() {
    val letters = Array<String>(3) { i -> ("$i").toString() }
    test16(letters)
}

输出结果

Argument 0 is 0
Argument 1 is 1
Argument 2 is 2
a0a1a2a3a4a5a6a7a8a9a10a11a12a13a14a15a16a17a18a19a20a21a22a23a24a25
a/b/c
Argument 0 is 0
Argument 1 is 1
Argument 2 is 2
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值