Kotlin D2

Kotlin 第二天

Kotlin 编程基础

一、课程目标

1.掌握 Kotlin 的基本语法格式

2.掌握 Kotlin 中的变量

3.掌握 Kotlin 中的运算符、字符串

4.掌握 Kotlin 中的选择结构语句、循环结构语句

5.掌握 Kotlin 中的变量类型转换、空值处理

二、Kotlin 基本语法格式

1. 程序入口

在 Kotlin 中,程序的入口点是main函数,它是程序开始执行的地方。就如同其他编程语言(如 Java、C 等)都有特定的程序入口一样。

kotlin 复制代码
fun main() {
    println("Hello, Kotlin!")
}
  • fun:Kotlin 里用于定义函数的关键字。无论是普通函数、成员函数还是顶层函数,都用fun声明。
  • main:作为程序入口,此函数名称固定。
  • ():表示函数的参数列表,这里main函数无参数,所以括号为空。
  • {}:大括号内是函数体,包含函数要执行的具体代码。
  • println("Hello, Kotlin!")println是 Kotlin 标准库中用于向控制台输出一行文本的函数,此处输出的文本为"Hello, Kotlin!"
带参数的main函数

Kotlin 的main函数可接收命令行参数,参数类型为Array<String>

kotlin 复制代码
fun main(args: Array<String>) {
    for (arg in args) {
        println(arg)
    }
}
  • args: Array<String>:表明main函数接收一个字符串数组作为参数,数组存储从命令行传递给程序的参数。
  • for (arg in args)for循环遍历args数组中的每个元素,将其赋值给变量arg并打印。

2. 注释

注释在编程中至关重要,能帮助开发者理解代码功能和逻辑,方便代码维护与协作开发。Kotlin 支持单行注释和多行注释。

单行注释

使用双斜杠//表示,从//开始到本行结束的内容会被编译器忽略。

kotlin 复制代码
// 这是一个单行注释
val message = "This is a message"
多行注释

使用/**/表示,它们之间的内容会被编译器忽略,可跨越多行。

kotlin 复制代码
/*
这是一个多行注释
可以包含多行文本
用于对代码块进行详细的说明
*/
val number = 10
嵌套注释

Kotlin 不支持嵌套的多行注释,例如以下代码是错误的:

kotlin 复制代码
/*
  外层注释开始
  /* 内层注释开始 */
  外层注释结束
*/

3. 语句结尾

在 Kotlin 中,语句结尾的分号;是可选的。一般情况下,可省略分号让代码更简洁。

kotlin 复制代码
// 省略分号
val name = "John"
println(name)

// 也可以使用分号
val age = 30; println(age)

多数场景下,建议省略分号,遵循 Kotlin 的简洁风格。但一行中写多个语句时,需用分号分隔。

4. 包声明

和 Java 类似,Kotlin 用包(package)组织代码,包声明通常位于文件顶部。

kotlin 复制代码
package com.example.kotlinapp

fun main() {
    println("This is a Kotlin app in com.example.kotlinapp package.")
}
  • package com.example.kotlinapp:声明该文件属于com.example.kotlinapp包。包命名常遵循反向域名规则,以避免命名冲突。
  • 包声明有助于将相关的类、函数和其他代码组织在一起,便于管理和维护。

5. 导入语句

若要使用其他包中的类、函数或其他元素,需用import语句导入。

kotlin 复制代码
package com.example.kotlinapp

import java.util.Date

fun main() {
    val currentDate = Date()
    println("Current date: $currentDate")
}
  • import java.util.Date:导入 Java 标准库中的Date类,此后在当前文件中可直接使用Date类,无需使用全限定名java.util.Date
  • Kotlin 支持导入特定包下的所有内容,使用import packageName.*,但不推荐,因为可能引发命名冲突 。

6. 函数定义

main函数外,Kotlin 还可定义其他函数,函数可以有参数和返回值。

kotlin 复制代码
// 定义一个带有两个参数并返回Int类型结果的函数
fun add(a: Int, b: Int): Int {
    return a + b
}

fun main() {
    val result = add(3, 5)
    println("The result of addition is: $result")
}
  • fun add(a: Int, b: Int): Int:定义名为add的函数,接收两个Int类型参数ab,返回Int类型结果。
  • return a + b:函数体中用return关键字返回ab的和。
  • main函数中调用add函数,将结果存于result变量,最后打印出来。

三、Kotlin 中的变量

1. 变量声明

Kotlin 中使用valvar关键字来声明变量。

  • val:用于声明不可变变量,类似于 Java 中的final变量,一旦赋值就不能再修改。
  • var:用于声明可变变量,可以多次赋值。
kotlin 复制代码
// 使用val声明不可变变量
val immutableVariable: Int = 10
// 以下代码会报错,因为immutableVariable是不可变的
// immutableVariable = 20 

// 使用var声明可变变量
var mutableVariable: String = "Hello"
// 可以对可变变量重新赋值
mutableVariable = "World"

2. 类型推断

Kotlin 具有智能的类型推断功能,在声明变量时可以省略类型声明。

kotlin 复制代码
// Kotlin会自动推断变量类型为Int
val number = 10
// 自动推断变量类型为String
var text = "Kotlin"

四、Kotlin 中的运算符

1. 算术运算符

算术运算符用于执行基本的数学运算,Kotlin 支持常见的加、减、乘、除、取模等运算。

kotlin 复制代码
fun main() {
    val a = 10
    val b = 3

    // 加法运算
    val sum = a + b
    println("a + b 的结果: $sum")

    // 减法运算
    val difference = a - b
    println("a - b 的结果: $difference")

    // 乘法运算
    val product = a * b
    println("a * b 的结果: $product")

    // 除法运算
    val quotient = a / b
    println("a / b 的结果: $quotient")

    // 取模运算(取余数)
    val remainder = a % b
    println("a % b 的结果: $remainder")
}
  • 加法运算符(+ :用于计算两个数的和,如 a + b 计算变量 ab 的总和。
  • 减法运算符(- :用于计算两个数的差,即 a - b 得到 a 减去 b 的结果。
  • 乘法运算符(\* :用于计算两个数的乘积,a * b 表示 a 乘以 b
  • 除法运算符(/ :用于计算两个数的商,当两个操作数都是整数时,结果会向下取整。例如 10 / 3 的结果是 3 而不是 3.333...
  • 取模运算符(% :用于计算两个数相除的余数,a % b 得到 a 除以 b 的余数。

2. 比较运算符

比较运算符用于比较两个值的大小或相等关系,其结果是布尔类型(truefalse)。

kotlin 复制代码
fun main() {
    val x = 5
    val y = 8

    // 等于比较
    val isEqual = x == y
    println("x 是否等于 y: $isEqual")

    // 不等于比较
    val isNotEqual = x != y
    println("x 是否不等于 y: $isNotEqual")

    // 大于比较
    val isGreater = x > y
    println("x 是否大于 y: $isGreater")

    // 小于比较
    val isLess = x < y
    println("x 是否小于 y: $isLess")

    // 大于等于比较
    val isGreaterOrEqual = x >= y
    println("x 是否大于等于 y: $isGreaterOrEqual")

    // 小于等于比较
    val isLessOrEqual = x <= y
    println("x 是否小于等于 y: $isLessOrEqual")
}
  • 等于运算符(== :判断两个值是否相等,如果相等返回 true,否则返回 false
  • 不等于运算符(!= :判断两个值是否不相等,若不相等返回 true,相等则返回 false
  • 大于运算符(> :判断左边的值是否大于右边的值,满足条件返回 true,否则返回 false
  • 小于运算符(< :判断左边的值是否小于右边的值,满足条件返回 true,否则返回 false
  • 大于等于运算符(>= :判断左边的值是否大于或等于右边的值,满足条件返回 true,否则返回 false
  • 小于等于运算符(<= :判断左边的值是否小于或等于右边的值,满足条件返回 true,否则返回 false

3. 逻辑运算符

逻辑运算符用于组合布尔表达式,常用于条件判断中。

kotlin 复制代码
fun main() {
    val condition1 = true
    val condition2 = false

    // 逻辑与运算
    val andResult = condition1 && condition2
    println("condition1 && condition2 的结果: $andResult")

    // 逻辑或运算
    val orResult = condition1 || condition2
    println("condition1 || condition2 的结果: $orResult")

    // 逻辑非运算
    val notResult = !condition1
    println("!condition1 的结果: $notResult")
}
  • 逻辑与运算符(&& :只有当两个操作数都为 true 时,结果才为 true,否则为 false。例如 condition1 && condition2 中,因为 condition2false,所以结果为 false
  • 逻辑或运算符(|| :只要两个操作数中有一个为 true,结果就为 true,只有当两个操作数都为 false 时,结果才为 false。如 condition1 || condition2 中,由于 condition1true,所以结果为 true
  • 逻辑非运算符(! :对一个布尔值取反,若操作数为 true,则结果为 false;若操作数为 false,则结果为 true

4. 位运算符

位运算符用于对整数类型(如 IntLong 等)的二进制位进行操作。

kotlin 复制代码
fun main() {
    val num1 = 5  // 二进制表示: 0101
    val num2 = 3  // 二进制表示: 0011

    // 按位与运算
    val bitwiseAnd = num1 and num2
    println("num1 and num2 的结果: $bitwiseAnd")

    // 按位或运算
    val bitwiseOr = num1 or num2
    println("num1 or num2 的结果: $bitwiseOr")

    // 按位异或运算
    val bitwiseXor = num1 xor num2
    println("num1 xor num2 的结果: $bitwiseXor")

    // 按位取反运算
    val bitwiseNot = num1.inv()
    println("num1 的按位取反结果: $bitwiseNot")

    // 左移运算
    val leftShift = num1 shl 2
    println("num1 左移 2 位的结果: $leftShift")

    // 右移运算
    val rightShift = num1 shr 1
    println("num1 右移 1 位的结果: $rightShift")

    // 无符号右移运算
    val unsignedRightShift = num1 ushr 1
    println("num1 无符号右移 1 位的结果: $unsignedRightShift")
}
  • 与运算符(and)**:对两个操作数的对应二进制位进行与运算,只有当对应位都为 1 时,结果位才为 1,否则为 0。
  • 按位或运算符(or:对两个操作数的对应二进制位进行或运算,只要对应位中有一个为 1,结果位就为 1,只有当对应位都为 0 时,结果位才为 0。
  • 按位异或运算符(xor:对两个操作数的对应二进制位进行异或运算,若对应位相同则结果位为 0,不同则结果位为 1。
  • 按位取反运算符(inv():对操作数的每个二进制位取反,即 0 变为 1,1 变为 0。
  • 左移运算符(shl:将操作数的二进制位向左移动指定的位数,右边空出的位用 0 填充。左移 n 位相当于乘以 2 的 n 次方。
  • 右移运算符(shr:将操作数的二进制位向右移动指定的位数,左边空出的位用符号位填充(正数补 0,负数补 1)。右移 n 位相当于除以 2 的 n 次方。
  • 无符号右移运算符(ushr:将操作数的二进制位向右移动指定的位数,左边空出的位用 0 填充。

5. 赋值运算符

赋值运算符用于将一个值赋给变量,同时还支持复合赋值运算符。

kotlin 复制代码
fun main() {
    var num = 10

    // 简单赋值
    num = 20
    println("简单赋值后 num 的值: $num")

    // 加法赋值
    num += 5
    println("加法赋值后 num 的值: $num")

    // 减法赋值
    num -= 3
    println("减法赋值后 num 的值: $num")

    // 乘法赋值
    num *= 2
    println("乘法赋值后 num 的值: $num")

    // 除法赋值
    num /= 4
    println("除法赋值后 num 的值: $num")

    // 取模赋值
    num %= 3
    println("取模赋值后 num 的值: $num")
}
  • 简单赋值运算符(=:将右边的值赋给左边的变量。
  • 复合赋值运算符(+=-=\*=/=%= :先进行相应的算术运算,再将结果赋给左边的变量。例如 num += 5 相当于 num = num + 5

6. 安全调用运算符和非空断言运算符

这两个运算符主要用于处理可空类型,增强代码的安全性。

kotlin 复制代码
fun main() {
    var nullableStr: String? = null

    // 安全调用运算符
    val length1 = nullableStr?.length
    println("使用安全调用运算符获取长度: $length1")

    nullableStr = "Hello"
    val length2 = nullableStr?.length
    println("使用安全调用运算符获取长度: $length2")

    // 非空断言运算符
    // nullableStr = null
    // val length3 = nullableStr!!.length // 如果 nullableStr 为 null,会抛出空指针异常
    val length4 = nullableStr!!.length
    println("使用非空断言运算符获取长度: $length4")
}
  • 安全调用运算符(?. :用于在调用可空类型的属性或方法时避免空指针异常。如果可空类型的值为 null,则整个表达式返回 null,不会执行后续的属性或方法调用。
  • 非空断言运算符(!! :用于告诉编译器该可空类型的值一定不为 null。如果实际上该值为 null,则会抛出空指针异常。

7. Elvis 运算符

Elvis 运算符用于在可空类型的值为 null 时提供一个默认值。

kotlin 复制代码
fun main() {
    var nullableStr: String? = null
    val result = nullableStr ?: "默认值"
    println("使用 Elvis 运算符的结果: $result")

    nullableStr = "Kotlin"
    val result2 = nullableStr ?: "默认值"
    println("使用 Elvis 运算符的结果: $result2")
}

Elvis 运算符(?:)会先判断左边的可空类型的值是否为 null,如果为 null,则返回右边的默认值;如果不为 null,则返回左边的值。

综上所述,Kotlin 中的运算符功能丰富,灵活运用这些运算符可以编写出高效、简洁的代码。在实际开发中,需要根据具体的需求选择合适的运算符。

五、Kotlin 中的字符串

在 Kotlin 中,字符串是一种非常常用的数据类型,用于表示文本信息。Kotlin 对字符串的处理提供了丰富的特性和便捷的操作方法,下面将详细讲解 Kotlin 中字符串的各个方面。

1. 字符串定义

在 Kotlin 里,可以使用双引号("")来定义字符串。字符串可以包含任意字符,包括字母、数字、标点符号等。

kotlin 复制代码
// 定义一个简单的字符串
val simpleString = "Hello, Kotlin!"

// 定义一个包含特殊字符的字符串
val specialString = "This is a string with \"quotes\" and \nnew line."
  • val simpleString = "Hello, Kotlin!":使用双引号直接定义一个字符串,并将其赋值给变量 simpleString
  • val specialString = "This is a string with \"quotes\" and \nnew line.":在字符串中,如果需要包含双引号("),需要使用反斜杠(\)进行转义;如果需要换行,可以使用转义字符 \n

2. 字符串模板

Kotlin 支持字符串模板,这是一种非常方便的特性,允许在字符串中嵌入变量或表达式。使用 $ 符号来引用变量,对于复杂的表达式,可以使用 ${}

kotlin 复制代码
val name = "Alice"
// 使用字符串模板将变量 name 插入到字符串中
val greeting = "Hello, $name!"
println(greeting)

val num1 = 5
val num2 = 3
// 对于复杂的表达式,使用 ${}
val result = "两数之和: ${num1 + num2}"
println(result)
  • val greeting = "Hello, $name!":在字符串中使用 $name 引用变量 name 的值,当字符串被打印时,$name 会被替换为 name 变量实际存储的值。
  • val result = "两数之和: ${num1 + num2}":对于复杂的表达式,如 num1 + num2,需要使用 ${} 将表达式括起来,这样在字符串中就会计算表达式的值并插入到相应位置。

3. 原始字符串

Kotlin 提供了原始字符串的定义方式,使用三个双引号(""")。原始字符串可以包含换行符和特殊字符,无需进行转义。

kotlin 复制代码
val rawString = """
    This is a raw string.
    It can contain multiple lines
    without using escape characters.
    "Double quotes" don't need to be escaped.
"""
println(rawString)
  • val rawString = """ ... """:使用三个双引号定义原始字符串,在这个字符串中,换行符和双引号等特殊字符都可以直接使用,无需进行转义。

4. 字符串方法

Kotlin 为字符串提供了许多实用的方法,用于对字符串进行各种操作,如获取长度、截取子字符串、转换大小写等。

4.1 获取字符串长度
kotlin 复制代码
val str = "Kotlin Programming"
val length = str.length
println("字符串长度: $length")
  • val length = str.length:通过 length 属性获取字符串 str 的长度,并将其赋值给变量 length
4.2 截取子字符串

使用 substring 方法可以截取字符串的一部分。

kotlin 复制代码
val str = "Kotlin Programming"
// 从索引 0 开始截取到索引 6(不包含索引 6)
val subStr = str.substring(0, 6)
println("截取的子字符串: $subStr")
  • val subStr = str.substring(0, 6)substring 方法接受两个参数,第一个参数是起始索引(包含),第二个参数是结束索引(不包含),这里从索引 0 开始截取到索引 6,得到的子字符串是 "Kotlin"
4.3 转换大小写

可以使用 toUpperCasetoLowerCase 方法将字符串转换为大写或小写。

kotlin 复制代码
val str = "Kotlin Programming"
// 将字符串转换为大写
val upperCaseStr = str.toUpperCase()
// 将字符串转换为小写
val lowerCaseStr = str.toLowerCase()
println("大写字符串: $upperCaseStr")
println("小写字符串: $lowerCaseStr")
  • val upperCaseStr = str.toUpperCase():调用 toUpperCase 方法将字符串 str 转换为大写形式。
  • val lowerCaseStr = str.toLowerCase():调用 toLowerCase 方法将字符串 str 转换为小写形式。
4.4 字符串查找和替换

使用 indexOf 方法可以查找某个字符或子字符串在字符串中第一次出现的索引位置;使用 replace 方法可以替换字符串中的指定内容。

kotlin 复制代码
val str = "Kotlin Programming"
// 查找 "Pro" 第一次出现的索引位置
val index = str.indexOf("Pro")
println("Pro 第一次出现的索引位置: $index")

// 将 "Kotlin" 替换为 "Java"
val replacedStr = str.replace("Kotlin", "Java")
println("替换后的字符串: $replacedStr")
  • val index = str.indexOf("Pro")indexOf 方法返回子字符串 "Pro" 在字符串 str 中第一次出现的索引位置,如果未找到则返回 -1。
  • val replacedStr = str.replace("Kotlin", "Java")replace 方法将字符串 str 中所有的 "Kotlin" 替换为 "Java",并返回替换后的新字符串。
4.5 字符串分割

使用 split 方法可以将字符串按照指定的分隔符分割成多个子字符串,并返回一个列表。

kotlin 复制代码
val str = "apple,banana,orange"
// 按照逗号分割字符串
val fruits = str.split(",")
for (fruit in fruits) {
    println(fruit)
}
  • val fruits = str.split(",")split 方法接受一个分隔符作为参数,这里使用逗号(,)作为分隔符,将字符串 str 分割成多个子字符串,并存储在列表 fruits 中。然后使用 for 循环遍历列表并打印每个子字符串。

5. 字符串比较

在 Kotlin 中,可以使用 == 比较两个字符串的内容是否相等,使用 === 比较两个字符串是否引用同一个对象。

kotlin 复制代码
val str1 = "Kotlin"
val str2 = "Kotlin"
val str3 = String("Kotlin".toCharArray())

// 比较字符串内容
val isContentEqual1 = str1 == str2
val isContentEqual2 = str1 == str3
println("str1 和 str2 内容是否相等: $isContentEqual1")
println("str1 和 str3 内容是否相等: $isContentEqual2")

// 比较字符串引用
val isReferenceEqual1 = str1 === str2
val isReferenceEqual2 = str1 === str3
println("str1 和 str2 引用是否相等: $isReferenceEqual1")
println("str1 和 str3 引用是否相等: $isReferenceEqual2")
  • str1 == str2str1 == str3:使用 == 比较字符串内容,只要两个字符串的字符序列相同,就返回 true
  • str1 === str2str1 === str3:使用 === 比较字符串引用,只有当两个字符串引用同一个对象时才返回 true。在上述代码中,str1str2 可能指向同一个字符串常量对象,而 str3 是通过 String 构造函数创建的新对象,所以 str1 === str3false

综上所述,Kotlin 中的字符串具有丰富的特性和强大的操作方法,能够满足各种文本处理的需求。通过合理运用这些特性和方法,可以编写出更加高效、简洁的代码。

六、Kotlin 中的选择结构语句

在 Kotlin 中,选择结构语句用于根据不同的条件执行不同的代码块,这在程序中非常重要,可以让程序根据不同的情况做出不同的响应。Kotlin 主要提供了两种选择结构语句:if - else 语句和 when 语句。下面将详细介绍这两种语句。

1. if - else 语句

1.1 基本的 if 语句

基本的 if 语句用于在条件为真时执行特定的代码块。

kotlin 复制代码
val age = 20
if (age >= 18) {
    println("你已经成年了")
}
  • if 是关键字,用于开始一个条件判断。
  • (age >= 18) 是条件表达式,这里判断变量 age 是否大于或等于 18。
  • {} 内的代码是条件为真时要执行的代码块。如果 age 确实大于或等于 18,就会执行 println("你已经成年了") 这行代码。
1.2 if - else 语句

if - else 语句用于在条件为真时执行一个代码块,条件为假时执行另一个代码块。

kotlin 复制代码
val age = 15
if (age >= 18) {
    println("你已经成年了")
} else {
    println("你还未成年")
}
  • 如果 age >= 18 条件为真,执行 if 代码块中的 println("你已经成年了")
  • 如果条件为假,执行 else 代码块中的 println("你还未成年")
1.3 嵌套的 if - else 语句

可以在 ifelse 代码块中嵌套另一个 if - else 语句,以实现更复杂的条件判断。

kotlin 复制代码
val score = 85
if (score >= 90) {
    println("成绩优秀")
} else {
    if (score >= 70) {
        println("成绩良好")
    } else {
        if (score >= 60) {
            println("成绩及格")
        } else {
            println("成绩不及格")
        }
    }
}
  • 首先判断 score 是否大于或等于 90,如果是则输出 "成绩优秀"。
  • 如果 score 小于 90,进入外层 else 代码块,再判断 score 是否大于或等于 70,依此类推,根据不同的分数段输出不同的信息。
1.4 if - else if - else

为了使嵌套的 if - else 语句更清晰,Kotlin 提供了 if - else if - else 链的形式。

kotlin 复制代码
val score = 85
if (score >= 90) {
    println("成绩优秀")
} else if (score >= 70) {
    println("成绩良好")
} else if (score >= 60) {
    println("成绩及格")
} else {
    println("成绩不及格")
}
  • 程序会依次检查每个条件。如果 score >= 90 为真,执行对应的代码块并结束整个 if - else if - else 链。
  • 如果 score >= 90 为假,继续检查 score >= 70,以此类推,直到找到一个为真的条件或执行 else 代码块。
1.5 if 作为表达式

在 Kotlin 中,if 语句可以作为表达式返回一个值,这使得代码更加简洁。

kotlin 复制代码
val age = 20
val message = if (age >= 18) {
    "你已经成年了"
} else {
    "你还未成年"
}
println(message)
  • if 表达式根据 age >= 18 的结果返回不同的字符串。
  • 如果条件为真,返回 "你已经成年了";如果条件为假,返回 "你还未成年"。最后将返回的值赋给变量 message 并打印。

2. when 语句

2.1 基本的 when 语句

when 语句类似于 Java 中的 switch 语句,但功能更强大,用于根据不同的情况执行不同的代码块。

kotlin 复制代码
val day = 3
when (day) {
    1 -> println("星期一")
    2 -> println("星期二")
    3 -> println("星期三")
    4 -> println("星期四")
    5 -> println("星期五")
    6, 7 -> println("周末")
    else -> println("无效的日期")
}
  • when 是关键字,后面的 (day) 是要进行判断的表达式。
  • 1 -> println("星期一") 表示当 day 的值为 1 时,执行 println("星期一") 代码。
  • 6, 7 -> println("周末") 表示当 day 的值为 6 或 7 时,执行 println("周末") 代码。
  • else 分支用于处理其他未匹配到的情况,类似于 switch 语句中的 default 分支。
2.2 when 作为表达式

if 语句一样,when 语句也可以作为表达式返回一个值。

kotlin 复制代码
val day = 3
val dayName = when (day) {
    1 -> "星期一"
    2 -> "星期二"
    3 -> "星期三"
    4 -> "星期四"
    5 -> "星期五"
    6, 7 -> "周末"
    else -> "无效的日期"
}
println(dayName)
  • when 表达式根据 day 的值返回对应的字符串,最后将返回的值赋给变量 dayName 并打印。
2.3 无参数的 when 语句

when 语句可以不指定参数,直接在每个分支中使用布尔表达式进行判断。

kotlin 复制代码
val score = 85
when {
    score >= 90 -> println("成绩优秀")
    score >= 70 -> println("成绩良好")
    score >= 60 -> println("成绩及格")
    else -> println("成绩不及格")
}
  • 这种形式的 when 语句会依次检查每个分支的布尔表达式,执行第一个为真的分支代码。如果所有分支都不满足条件,则执行 else 分支。
2.4 类型检查和转换

when 语句还可以用于类型检查和转换,结合 is 关键字使用。

kotlin 复制代码
fun printValue(value: Any) {
    when (value) {
        is Int -> println("这是一个整数: $value")
        is String -> println("这是一个字符串: $value")
        is Double -> println("这是一个双精度浮点数: $value")
        else -> println("未知类型")
    }
}

val num = 10
printValue(num)
  • is 关键字用于检查 value 是否为指定的类型。
  • 如果 valueInt 类型,执行对应的代码块并输出相关信息;如果是 String 类型或 Double 类型,也会执行相应的代码块;如果都不匹配,则执行 else 分支。

综上所述,if - else 语句和 when 语句是 Kotlin 中非常重要的选择结构语句,开发者可以根据具体的需求和场景选择合适的语句来实现条件判断和代码分支控制。

七、Kotlin 中的循环结构语句

在 Kotlin 中,循环结构语句用于重复执行特定的代码块,以处理批量数据或执行重复性任务。Kotlin 提供了多种循环结构,包括 for 循环、while 循环和 do - while 循环,下面将详细介绍这些循环结构的用法。

1. for 循环

for 循环主要用于遍历集合或范围,它提供了简洁且灵活的方式来处理一系列元素。

1.1 遍历范围

可以使用 for 循环遍历一个整数范围。

kotlin 复制代码
// 遍历从 1 到 5 的整数(包含 1 和 5)
for (i in 1..5) {
    println(i)
}
  • for 是关键字,用于开始一个 for 循环。
  • i 是循环变量,在每次循环迭代中,i 会依次取范围 1..5 中的值。
  • 1..5 表示一个从 1 到 5 的闭区间,包含 1 和 5。
  • 循环体 { println(i) } 会在每次循环时执行,打印出当前 i 的值。
1.2 遍历步长不为 1 的范围

可以使用 step 关键字指定遍历范围的步长。

kotlin 复制代码
// 从 1 开始,以步长 2 遍历到 10
for (i in 1..10 step 2) {
    println(i)
}
  • step 2 表示每次循环 i 的值增加 2,即遍历序列为 1、3、5、7、9。
1.3 反向遍历范围

使用 downTo 关键字可以实现反向遍历范围。

kotlin 复制代码
// 从 5 反向遍历到 1
for (i in 5 downTo 1) {
    println(i)
}
  • downTo 让循环变量从较大值向较小值递减,这里 i 依次取值为 5、4、3、2、1。
1.4 遍历集合

for 循环可以方便地遍历各种集合,如列表、数组等。

kotlin 复制代码
val numbers = listOf(10, 20, 30)
for (number in numbers) {
    println(number)
}
  • numbers 是一个整数列表,for 循环会依次取出列表中的每个元素,并将其赋值给循环变量 number,然后执行循环体打印该元素。
1.5 遍历集合时获取索引

使用 withIndex() 方法可以在遍历集合时同时获取元素的索引。

kotlin 复制代码
val fruits = listOf("apple", "banana", "orange")
for ((index, fruit) in fruits.withIndex()) {
    println("索引 $index 对应的水果是: $fruit")
}
  • withIndex() 方法将集合转换为包含索引和元素的序列。
  • (index, fruit) 是解构声明,用于分别获取索引和元素的值,然后在循环体中打印相关信息。

2. while 循环

while 循环在条件为真时重复执行代码块,每次循环开始前都会检查条件是否满足。

kotlin 复制代码
var count = 0
while (count < 5) {
    println(count)
    count++
}
  • var count = 0:初始化一个计数器变量 count 为 0。
  • while (count < 5):循环条件,只要 count 小于 5,就会执行循环体。
  • 循环体 { println(count); count++ } 会打印当前 count 的值,并将 count 的值加 1。
  • count 变为 5 时,条件 count < 5 为假,循环结束。

3. do - while 循环

do - while 循环与 while 循环类似,但它会先执行一次循环体,然后再检查条件。这意味着无论条件是否为真,循环体至少会执行一次。

kotlin 复制代码
var num = 0
do {
    println(num)
    num++
} while (num < 5)
  • var num = 0:初始化变量 num 为 0。
  • do 关键字后面的代码块是循环体,会先执行一次,这里打印 num 的值并将其加 1。
  • while (num < 5):执行完循环体后检查条件,如果 num 小于 5,则继续循环;否则,循环结束。

4. 循环控制语句

Kotlin 提供了一些循环控制语句,用于在循环中控制流程,如 breakcontinue

4.1 break 语句

break 语句用于立即终止当前所在的循环。

kotlin 复制代码
for (i in 1..10) {
    if (i == 5) {
        break
    }
    println(i)
}
  • i 的值等于 5 时,if 条件为真,执行 break 语句,循环立即终止,不会再继续执行后续的循环迭代。
4.2 continue 语句

continue 语句用于跳过当前循环迭代的剩余部分,直接进入下一次循环迭代。

kotlin 复制代码
for (i in 1..10) {
    if (i % 2 == 0) {
        continue
    }
    println(i)
}
  • i 是偶数时,if 条件为真,执行 continue 语句,跳过 println(i) 这行代码,直接进入下一次循环迭代,继续处理下一个 i 的值。

综上所述,Kotlin 中的循环结构语句提供了丰富的功能和灵活的使用方式,可以满足不同场景下的循环需求。合理运用这些循环结构和控制语句,能够编写出高效、简洁的代码。

八、Kotlin 中的变量类型转换

在 Kotlin 中,变量类型转换分为显式类型转换和安全类型转换,同时还有针对可空类型的特殊转换情况。下面将详细介绍 Kotlin 中各种类型转换的方式和应用场景。

1. 显式类型转换

Kotlin 不支持隐式类型转换,因此在需要进行类型转换时,必须使用显式的转换方法。显式类型转换可以在不同的基本数据类型以及类类型之间进行。

1.1 基本数据类型的显式转换

Kotlin 为基本数据类型提供了一系列的转换方法,例如 toByte()toShort()toInt()toLong()toFloat()toDouble()toChar() 等。

kotlin 复制代码
fun main() {
    // 整数类型之间的转换
    val intValue: Int = 10
    val byteValue: Byte = intValue.toByte()
    val shortValue: Short = intValue.toShort()
    val longValue: Long = intValue.toLong()

    // 整数转换为浮点数
    val floatValue: Float = intValue.toFloat()
    val doubleValue: Double = intValue.toDouble()

    // 整数转换为字符
    val charValue: Char = intValue.toChar()

    println("Byte 值: $byteValue")
    println("Short 值: $shortValue")
    println("Long 值: $longValue")
    println("Float 值: $floatValue")
    println("Double 值: $doubleValue")
    println("Char 值: $charValue")
}
  • toByte():将一个整数转换为 Byte 类型。如果原始整数的值超出了 Byte 类型的范围(-128 到 127),会发生数据截断。
  • toShort():将整数转换为 Short 类型,同样可能会有数据截断风险。
  • toLong():将整数转换为 Long 类型,不会丢失数据,因为 Long 类型的取值范围比 Int 大。
  • toFloat()toDouble():将整数转换为浮点数类型,会在转换过程中添加小数部分。
  • toChar():将整数转换为对应的 Unicode 字符。
1.2 字符串与基本数据类型的转换

可以将字符串转换为基本数据类型,也可以将基本数据类型转换为字符串。

kotlin 复制代码
fun main() {
    // 字符串转换为整数
    val strNumber: String = "20"
    val intResult: Int = strNumber.toInt()

    // 整数转换为字符串
    val num: Int = 30
    val strResult: String = num.toString()

    println("字符串转换为整数: $intResult")
    println("整数转换为字符串: $strResult")
}
  • toInt():将字符串转换为 Int 类型。如果字符串不能正确表示一个整数,会抛出 NumberFormatException 异常。
  • toString():将基本数据类型(如 IntFloat 等)转换为字符串。

2. 安全类型转换

在进行类型转换时,可能会遇到类型不兼容的情况,为了避免抛出 ClassCastException 异常,Kotlin 提供了安全类型转换操作符 as?

kotlin 复制代码
fun main() {
    val anyValue: Any = "Hello"

    // 安全类型转换为 String
    val strResult: String? = anyValue as? String
    println("安全转换为 String 结果: $strResult")

    // 尝试将 Any 类型转换为 Int
    val intResult: Int? = anyValue as? Int
    println("安全转换为 Int 结果: $intResult")
}
  • as? 操作符用于安全地进行类型转换。如果转换成功,返回转换后的类型;如果转换失败,返回 null
  • 在上述代码中,anyValue 实际是一个 String 类型,所以 anyValue as? String 转换成功,返回该字符串;而 anyValue as? Int 转换失败,返回 null

3. 类型检查与转换结合使用

在进行类型转换之前,通常需要先检查变量的类型,可以使用 is 关键字进行类型检查。

kotlin 复制代码
fun main() {
    val anyValue: Any = 10

    if (anyValue is Int) {
        // 类型检查通过后,可以安全地进行类型转换
        val intValue: Int = anyValue
        println("类型检查并转换后的 Int 值: $intValue")
    } else {
        println("不是 Int 类型")
    }
}
  • is 关键字用于检查变量是否为指定的类型。如果 anyValueInt 类型,if 条件为真,进入 if 代码块。
  • if 代码块中,由于已经通过类型检查,Kotlin 会自动将 anyValue 视为 Int 类型,无需显式转换。

4. 可空类型的转换

对于可空类型的变量,在进行类型转换时需要特别注意空值的处理。

kotlin 复制代码
fun main() {
    val nullableStr: String? = "100"

    // 可空字符串转换为可空整数
    val nullableInt: Int? = nullableStr?.toIntOrNull()
    println("可空字符串转换为可空整数: $nullableInt")

    val nullValue: String? = null
    val nullInt: Int? = nullValue?.toIntOrNull()
    println("空字符串转换为可空整数: $nullInt")
}
  • toIntOrNull() 方法用于将字符串转换为 Int 类型,如果字符串不能正确表示一个整数或字符串为 null,则返回 null
  • 通过使用安全调用运算符 ?.,可以避免在字符串为 null 时调用 toIntOrNull() 方法而导致空指针异常。

5. 集合类型的转换

在处理集合时,也可能需要进行类型转换,例如将一个 List<Any> 转换为 List<Int>

kotlin 复制代码
fun main() {
    val anyList: List<Any> = listOf(1, 2, 3)
    val intList: List<Int> = anyList.filterIsInstance<Int>()
    println("集合类型转换结果: $intList")
}
  • filterIsInstance<Int>() 方法用于过滤集合中的元素,只保留指定类型(这里是 Int 类型)的元素,并返回一个新的集合。

综上所述,Kotlin 提供了多种类型转换的方式,开发者可以根据具体的需求和场景选择合适的转换方法,同时要注意处理可能出现的异常和空值情况,以确保代码的健壮性。

九、Kotlin 中的空值处理

在编程中,空值处理是一个非常重要的话题,因为空值往往是导致程序出现空指针异常(NullPointerException)的根源。Kotlin 为了避免空指针异常,在语言层面提供了一系列强大的空值处理机制。以下将详细介绍 Kotlin 中的空值处理方法。

1. 可空类型与非空类型

在 Kotlin 中,类型系统明确区分了可空类型和非空类型。默认情况下,变量声明为非空类型,即不能将 null 赋值给它们;若要允许变量为 null,则需要使用可空类型,通过在类型后面添加 ? 来表示。

kotlin 复制代码
// 非空类型的变量,不能赋值为 null
var nonNullableString: String = "Hello"
// 下面这行代码会编译错误,因为 nonNullableString 是非空类型
// nonNullableString = null 

// 可空类型的变量,可以赋值为 null
var nullableString: String? = "World"
nullableString = null
  • var nonNullableString: String = "Hello":声明了一个非空的 String 类型变量 nonNullableString,它只能存储有效的字符串值,不能为 null
  • var nullableString: String? = "World":声明了一个可空的 String 类型变量 nullableString,在声明时可以初始化为有效的字符串,也可以后续将其赋值为 null

2. 安全调用运算符(?.

安全调用运算符 ?. 是 Kotlin 中处理可空类型的一个重要工具,用于在调用可空类型变量的属性或方法时,避免空指针异常。如果变量为 null,则整个表达式返回 null,不会执行后续的属性或方法调用。

kotlin 复制代码
var nullableString: String? = null
// 使用安全调用运算符获取字符串长度
val length1 = nullableString?.length
println("使用安全调用运算符获取长度: $length1")

nullableString = "Hello"
val length2 = nullableString?.length
println("使用安全调用运算符获取长度: $length2")
  • val length1 = nullableString?.length:当 nullableStringnull 时,nullableString?.length 直接返回 null,不会尝试访问 length 属性,从而避免了空指针异常。
  • val length2 = nullableString?.length:当 nullableString 不为 null 时,正常调用 length 属性获取字符串的长度。

3. Elvis 运算符(?:

Elvis 运算符 ?: 用于在可空类型的值为 null 时提供一个默认值。它会先判断左边的可空类型的值是否为 null,如果为 null,则返回右边的默认值;如果不为 null,则返回左边的值。

kotlin 复制代码
var nullableString: String? = null
// 使用 Elvis 运算符提供默认值
val result = nullableString ?: "默认值"
println("使用 Elvis 运算符的结果: $result")

nullableString = "Kotlin"
val result2 = nullableString ?: "默认值"
println("使用 Elvis 运算符的结果: $result2")
  • val result = nullableString ?: "默认值":由于 nullableStringnull,所以整个表达式返回右边的 "默认值"
  • val result2 = nullableString ?: "默认值":此时 nullableString 不为 null,表达式返回 nullableString 的值 "Kotlin"

4. 非空断言运算符(!!

非空断言运算符 !! 用于告诉编译器该可空类型的值一定不为 null。如果实际上该值为 null,则会抛出空指针异常。因此,使用该运算符时要非常谨慎,确保可空变量确实不为 null

kotlin 复制代码
var nullableString: String? = "Hello"
// 使用非空断言运算符获取字符串长度
val length = nullableString!!.length
println("使用非空断言运算符获取长度: $length")

// 下面这行代码会抛出空指针异常,因为将 nullableString 赋值为 null 后使用了 !! 运算符
// nullableString = null
// val errorLength = nullableString!!.length 
  • val length = nullableString!!.length:当 nullableString 不为 null 时,使用 !! 运算符可以正常访问其属性或方法。
  • 如果将 nullableString 赋值为 null 后再使用 !! 运算符,就会抛出 NullPointerException

5. let 函数与安全调用结合

let 函数经常与安全调用运算符结合使用,用于在可空变量不为 null 时执行一些操作。

kotlin 复制代码
var nullableString: String? = "Hello"
nullableString?.let {
    // 在 let 函数内部,it 代表非空的 nullableString
    println("字符串长度: ${it.length}")
}

nullableString = null
nullableString?.let {
    println("字符串长度: ${it.length}")
}
  • nullableString?.let { ... }:当 nullableString 不为 null 时,会执行 let 函数内部的代码块,it 代表非空的 nullableString;当 nullableStringnull 时,let 函数不会执行。

6. 可空类型集合的处理

在处理可空类型的集合时,可以使用 filterNotNull() 方法过滤掉集合中的 null 值。

kotlin 复制代码
val nullableList: List<String?> = listOf("Apple", null, "Banana", null, "Cherry")
val nonNullList = nullableList.filterNotNull()
println("过滤掉 null 值后的集合: $nonNullList")
  • filterNotNull() 方法会遍历集合,将其中的非 null 元素提取出来,组成一个新的非空元素集合。

7. 函数参数和返回值的空值处理

在定义函数时,也可以明确指定参数和返回值是否可为空。

kotlin 复制代码
// 参数为可空类型,返回值为非空类型
fun printAndReturnLength(str: String?): Int {
    return str?.length ?: 0
}

val result = printAndReturnLength(null)
println("字符串长度(如果为 null 则返回 0): $result")
  • fun printAndReturnLength(str: String?): Int:函数的参数 str 为可空的 String 类型,返回值为非空的 Int 类型。
  • 在函数内部,使用安全调用运算符和 Elvis 运算符处理 str 可能为 null 的情况,确保返回值不为 null

综上所述,Kotlin 通过可空类型、安全调用运算符、Elvis 运算符等机制,为开发者提供了一套全面且安全的空值处理方案,大大降低了空指针异常的风险,提高了代码的健壮性和可靠性。

十、总结

通过本次课程的学习,我们掌握了 Kotlin 的基本语法格式,了解了变量、运算符、字符串的使用方法,学会了运用选择结构语句和循环结构语句,同时也掌握了变量类型转换和空值处理的技巧。在后续的学习中,可以通过更多的实践来巩固这些知识。

课后提问

如何在Kotlin中声明常量?

Kotlin中的变量类型转换有哪些注意事项?

除了上述提到的,Kotlin还有哪些其他的重要特性?

相关推荐
今天也想MK代码1 小时前
rust编程实战:实现3d粒子渲染wasm
开发语言·rust·wasm
结衣结衣.1 小时前
【Qt】自定义信号和槽函数
开发语言·c++·qt·c++11
尘鹄2 小时前
一文讲懂Go语言如何使用配置文件连接数据库
开发语言·数据库·后端·golang
qq_433554542 小时前
C++ 二叉搜索树代码
开发语言·c++·算法
好看资源平台2 小时前
手写识别革命:Manus AI如何攻克多语言混合识别难题(二)
开发语言·人工智能·php
Hopebearer_2 小时前
vue3中ref和reactive的区别
开发语言·前端·javascript·vue.js·前端框架·ecmascript
lly2024062 小时前
CentOS Docker 安装指南
开发语言
我命由我123452 小时前
Java Maven 项目问题:com.diogonunes:JColor:jar:5.5.1 was not found in...
java·开发语言·java-ee·maven·intellij-idea·jar·intellij idea
烂蜻蜓4 小时前
深入理解 HTML 元素:构建网页的基础
开发语言·前端·css·html·html5
Jason-河山7 小时前
如何在PHP爬虫中处理异常情况的详细指南
开发语言·爬虫·php