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)