Kotlin入门教程 一、Kotlin的主函数 1.1 IDEA文件展开
1.2 Kotlin的执行流程 Kotlin的源代码先通过JDK编译成Java字节码,然后再由JVM(Java虚拟机)执行转换成机器码,最终由计算机执行。
执行流程图:
1 Kotlin源代码(.kt) → Java字节码(.class) → JVM虚拟机 → 机器码 → 计算机执行
1.3 第一个Kotlin程序 在Kotlin中,程序的入口点是main函数。下面是一个最简单的Kotlin程序:
1 2 3 fun main (args: Array <String >) { println("Hello, World!" ) }
代码解析:
fun:关键字,用于声明函数main:函数名,程序入口点args: Array<String>:参数,是一个字符串数组println():打印输出函数,输出内容后自动换行二、变量与基础数据类型 2.1 变量声明 在Kotlin中,变量可以使用val或var关键字来声明:
关键字 含义 是否可变 使用场景 valvalue(值) 不可变 声明后不可重新赋值,类似Java的final varvariable(变量) 可变 声明后可以重新赋值
1 2 3 4 5 6 7 8 val a: Int = 10 var b: Int = 20 b = 30
最佳实践: 优先使用val,只有在确实需要修改变量值时才使用var,这样可以减少程序中的可变状态,降低出错风险。
2.2 基础数据类型 Kotlin提供了以下基础数据类型:
整数类型 类型 位数 范围 最大值常量 最小值常量 Byte 8位 -128 到 127 Byte.MAX_VALUE = 127 Byte.MIN_VALUE = -128 Short 16位 -32768 到 32767 Short.MAX_VALUE = 32767 Short.MIN_VALUE = -32768 Int 32位 -2147483648 到 2147483647 Int.MAX_VALUE = 2147483647 Int.MIN_VALUE = -2147483648 Long 64位 -9223372036854775808 到 9223372036854775807 Long.MAX_VALUE = 9223372036854775807 Long.MIN_VALUE = -9223372036854775808
浮点类型 类型 位数 说明 最大值 最小值 Float 32位 单精度浮点数 3.4028235e38 1.4e-45 Double 64位 双精度浮点数 1.7976931348623157e308 4.9e-324
其他类型 类型 位数 说明 范围/取值 Char 16位 Unicode字符 ‘\u0000’ 到 ‘\uFFFF’ Boolean 1位 布尔值 true 或 false
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 val byteNum: Byte = 127 val shortNum: Short = 32767 val intNum: Int = 2147483647 val longNum: Long = 9223372036854775807 val floatNum: Float = 3.14f val doubleNum: Double = 3.141592653589793 val charA: Char = 'A' val charChinese: Char = '中' val isTrue: Boolean = true val isFalse: Boolean = false
2.3 空值类型 Kotlin的一个重要特性是空安全(Null Safety)。在Kotlin中,空值类型用null表示,它表示一个不存在的值。
可空类型声明 1 2 var text: String? = null
空值检查 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 fun main (args: Array <String >) { val text: String? = null if (text != null ) { println(text.length) } else { println("text is null" ) } } fun main (args: Array <String >) { val text: String? = null println(text?.length) }
Elvis操作符(?:) Elvis操作符用于提供默认值,当左侧表达式为null时,使用右侧的值。
1 2 3 4 val text: String? = null val text2: String? = text ?: "default" println(text2)
三、函数 3.1 函数基础 在Kotlin中,函数使用fun关键字来声明。函数可以有参数也可以没有参数,可以有返回值也可以没有返回值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 fun functionName (parameter1: Type1 , parameter2: Type2 ) : ReturnType { return result } fun sum (a: Int , b: Int ) : Int { return a + b } fun sum (a: Int , b: Int ) = a + bfun printHello () { println("Hello!" ) }
3.2 参数默认值 Kotlin支持为函数参数指定默认值,调用时可以省略有默认值的参数。
1 2 3 4 5 6 7 8 9 fun sum (a: Int , b: Int = 0 ) : Int { return a + b } fun main () { println(sum(10 )) println(sum(10 , 5 )) }
3.3 可变参数(vararg) 在Kotlin中,函数可以使用vararg关键字来声明可变数量的参数。
1 2 3 4 5 6 7 8 9 10 11 fun main (args: Array <String >) { println(sum(1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 556 , 48 )) } fun sum (vararg nums: Int ) : Int { var result = 0 for (num in nums) { result += num } return result }
注意事项:
一个函数最多只能有一个vararg参数 vararg参数通常是函数的最后一个参数如果vararg参数不是最后一个,其后的参数需要使用命名参数传递 四、循环 4.1 for循环 在Kotlin中,for循环可以遍历任何提供迭代器的对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 fun main (args: Array <String >) { println("使用 until:" ) for (i in 0 until 10 ) { println(i) } println("使用 ..:" ) for (i in 0. .9 ) { println(i) } println("使用 step:" ) for (i in 0 until 10 step 2 ) { println(i) } println("使用 downTo:" ) for (i in 9 downTo 0 ) { println(i) } val arr = arrayOf(1 , 2 , 3 , 4 , 5 ) for (item in arr) { println(item) } for ((index, value) in arr.withIndex()) { println("索引:$index ,值:$value " ) } }
4.2 while循环 1 2 3 4 5 6 7 fun main (args: Array <String >) { var i = 0 while (i < 10 ) { println(i) i++ } }
4.3 循环控制 在Kotlin中,可以使用以下关键字控制循环:
关键字 作用 说明 break结束循环 立即终止当前循环 continue跳过当前迭代 跳过本次循环,继续下一次迭代 break@label跳出指定循环 跳出标签标记的外部循环
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 fun main () { for (i in 1. .10 ) { if (i == 5 ) break println(i) } for (i in 1. .10 ) { if (i == 5 ) continue println(i) } outer@ for (i in 1. .3 ) { for (j in 1. .3 ) { if (i == 2 && j == 2 ) break @outer println("i=$i , j=$j " ) } } }
五、数组与类型判断 5.1 数组创建 在Kotlin中,数组可以使用arrayOf函数来创建。
1 2 3 4 5 6 7 8 9 10 11 12 13 fun main (args: Array <String >) { val intArr = arrayOf(1 , 2 , 3 , 4 , 5 ) val strArr = arrayOf("Hello" , "World" , "Kotlin" ) val mixedArr = arrayOf(1 , "Hello" , 3.14 , true ) val sizedArr = Array(5 ) { it * 2 } }
5.2 类型判断(is关键字) 使用is关键字可以判断一个对象是否是某种类型。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 fun main (args: Array <String >) { val arr = arrayOf(1 , 2 , 3 , 4 , 5 ) if (arr is Array<Int >) { println("arr is Array<Int>" ) } val obj: Any = "Hello" if (obj is String) { println(obj.length) } }
IDEA快捷键: Ctrl+; 可以添加类型显示,让代码更清晰。
六、类与对象 6.1 类的基本定义 在Kotlin中,类使用class关键字来声明。类可以有属性和方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class Person { var name: String = "" var age: Int = 0 fun sayHello () { println("Hello, my name is $name , I am $age years old." ) } } fun main (args: Array <String >) { val person = Person() person.name = "张三" person.age = 18 person.sayHello() }
6.2 构造函数 主构造函数 主构造函数是类头部的一部分,紧跟在类名之后。
1 2 3 4 5 6 7 8 9 10 11 12 13 class Student (name: String, var age: Int = 0 ) { var name: String = name.trim() fun sayHello () { println("Hello, my name is $name , I am $age years old. I am a student." ) } } fun main () { val student = Student("张三" , 18 ) student.sayHello() }
初始化块(init) 初始化块用init关键字声明,属于类的一部分。每创建一个类的实例,所有初始化块都会执行。
重要: Kotlin次构造函数必须先调用主构造函数,因此init块一定会在所有次构造函数逻辑前执行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class Student (name: String, var age: Int = 0 ) { var name: String = name.trim() init { if (name.lowercase().startsWith("a" )) { this .name = name } else { this .name = "User" println("Name does not start with A, using 'User' as default." ) } } fun sayHello () { println("Hello, my name is $name , I am $age years old. I am a student." ) } }
次构造函数(constructor) 次构造函数用constructor关键字声明,核心规则:
一个类可以有多个次构造函数(重载) 所有次构造函数必须直接或间接调用主构造函数(通过this()) 次构造函数的逻辑执行在init块之后 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Student (name: String, var age: Int = 0 ) { var name: String = name.trim() init { if (name.lowercase().startsWith("a" )) { this .name = name } else { this .name = "User" println("Name does not start with A, using 'User' as default." ) } } constructor (name: String) : this (name, 0 ) { println("Secondary constructor called" ) } fun sayHello () { println("Hello, my name is $name , I am $age years old. I am a student." ) } }
6.3 Getter和Setter 在Kotlin中,类的属性可以使用var或val关键字来声明:
var关键字声明的属性可以读写val关键字声明的属性只能读Kotlin会自动为属性生成get()和set()方法,也可以自定义。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class Student (name: String, var age: Int = 0 ) { var name: String = name.trim() get () { return field } set (value) { field = value } } fun main () { val student = Student("张三" , 18 ) println(student.name) student.name = "李四" }
说明: field是Kotlin中专门用于访问属性「底层存储字段」的关键字,避免在getter/setter中造成递归调用。
6.4 lateinit延迟初始化 lateinit(延迟初始化)是Kotlin中用于标记可变属性(var)的关键字,允许属性在声明时不初始化,而是推迟到后续代码中初始化。
语法: lateinit var 变量名: 类型
使用限制:
仅支持var,不支持val 不支持基本数据类型(Int、Long、Double等) 必须在使用前初始化,否则会抛出异常 1 2 3 4 5 6 7 8 9 10 11 12 13 14 class MainActivity { lateinit var adapter: RecyclerView.Adapter<*> fun initAdapter () { adapter = MyAdapter() } fun useAdapter () { if (::adapter.isInitialized) { adapter.notifyDataSetChanged() } } }
6.5 伴随对象(companion object) 伴随对象是Kotlin中替代Java静态成员(static)的核心语法,本质是「隶属于类的单例对象」,可以包含属性、方法、常量等。
作用: 实现类级别的操作,无需创建类实例就能调用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class MyClass { companion object { const val MAX_COUNT = 100 fun create () : MyClass { return MyClass() } } } fun main () { println(MyClass.MAX_COUNT) val instance = MyClass.create() }
6.6 单例模式(object关键字) Kotlin中的object关键字是实现饿汉式单例的简洁方式,编译器会自动生成线程安全的单例对象。
语法: object 单例名 { ... }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 object DatabaseHelper { private val connection: Connection? = null fun connect () { } fun disconnect () { } } fun main () { DatabaseHelper.connect() DatabaseHelper.disconnect() }
单例模式的优势:
简单易用 :无需手动编写复杂的代码,直接使用object关键字即可线程安全 :Kotlin会自动处理多线程环境下的线程安全问题延迟初始化 :单例对象在第一次被访问时才会初始化全局唯一 :单例对象在整个应用程序生命周期内只有一个实例6.7 by lazy延迟初始化 by lazy是Kotlin中实现延迟初始化的一种方式,将属性的初始化延迟到第一次访问时。
语法: val 变量名: 类型 by lazy { 初始化表达式 }
注意: 仅支持val,不支持var
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class MyClass { val userNameByLazy: String by lazy { println("执行初始化逻辑" ) "张三" } val userNameNoLazy: String = run { println("立即执行初始化逻辑" ) "张三" } } fun main () { val myClass = MyClass() println("对象创建完成" ) println(myClass.userNameByLazy) println(myClass.userNameByLazy) }
by lazy的优势:
延迟初始化 :避免过早初始化导致的资源浪费线程安全 :默认情况下,Kotlin会处理多线程环境下的线程安全问题全局唯一 :属性在整个应用程序生命周期内只有一个实例6.8 枚举类(enum class) 枚举类是Kotlin中一种特殊的类,用于表示固定数量的枚举值(如方向、状态、颜色等)。
语法: enum class 枚举名 { 枚举值1, 枚举值2, ... }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 enum class Direction { NORTH, SOUTH, EAST, WEST } enum class Color (val rgb: Int ) { RED(0xFF0000 ), GREEN(0x00FF00 ), BLUE(0x0000FF ) } fun main () { val direction = Direction.NORTH println(direction) for (dir in Direction.values()) { println(dir) } val color = Color.RED println(color.rgb) }
枚举类的优势:
类型安全 :枚举类的每个值都是枚举类的一个实例可遍历 :枚举类的所有值都可以通过values()方法遍历可比较 :枚举类的每个值都可以进行比较操作可序列化 :枚举类的每个值都可以进行序列化操作可用于when语句 :枚举类的每个值都可以直接用于when语句6.9 when表达式 when是Kotlin中替代Java switch语句的增强版分支结构,功能更强大、语法更简洁。
语法:
1 2 3 4 5 6 when (表达式) { 匹配值1 -> 代码块1 匹配值2 -> 代码块2 ... else -> 代码块N }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 fun main () { val x = 5 when (x) { 1 -> println("x is 1" ) 2 -> println("x is 2" ) in 3. .10 -> println("x is between 3 and 10" ) else -> println("x is unknown" ) } val obj: Any = "Hello" when (obj) { is Int -> println("obj is Int" ) is String -> println("obj is String, length = ${obj.length} " ) is Double -> println("obj is Double" ) else -> println("obj is unknown type" ) } val result = when (x) { 1 -> "one" 2 -> "two" else -> "other" } }
when表达式的优势:
功能更强大 :支持值匹配、类型匹配、表达式返回值等多种场景语法更简洁 :比switch语句更简洁,代码更易读类型安全 :匹配值必须是枚举值或常量,避免类型转换错误可扩展性 :可以很方便地扩展新的匹配值6.10 内部类(inner class) inner内部类是Kotlin中一种特殊的内部类,它可以访问外部类的成员(包括属性、方法、构造函数等)。
语法: inner class 内部类名(参数1: 类型1, 参数2: 类型2, ...) { ... }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class Outer { private val outerProperty = "Outer Property" inner class Inner { fun accessOuter () { println(outerProperty) } } } fun main () { val outer = Outer() val inner = outer.Inner() inner .accessOuter() }
inner内部类的优势:
访问外部类成员 :可以直接访问外部类的属性、方法、构造函数等灵活实例化 :可以被外部类实例化,实现更灵活的代码组织避免命名冲突 :内部类的成员可以与外部类的成员重名6.11 可变列表(mutableListOf) mutableListOf<T>是Kotlin中一种可变列表(MutableList),可以存储任意类型的元素,并且可以动态地添加、删除、修改元素。
语法: mutableListOf<T>(元素1, 元素2, ...)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 fun main () { val names = mutableListOf("张三" , "李四" , "王五" ) names.add("赵六" ) names.remove("李四" ) names[0 ] = "张三丰" for (name in names) { println(name) } }
mutableListOf的优势:
动态操作 :可以根据需要动态地添加、删除、修改元素类型灵活 :可以存储任意类型的元素遍历方便 :可以使用for循环、forEach方法等方便地遍历七、继承、接口与抽象类 7.1 open关键字 在Kotlin中,类和方法默认是final的,不能被继承或重写。使用open关键字可以修饰类、属性、方法,表明它们可以被继承、重写或实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 open class Animal (val name: String) { open fun makeSound () { println("$name makes a sound" ) } } class Dog (name: String) : Animal(name) { override fun makeSound () { println("$name barks" ) } }
7.2 sealed关键字(密封类) sealed关键字用于修饰类,表明它们只能被同一文件中的子类继承,不能被外部类直接实例化。
作用: 限制类的继承层次,配合when表达式使用时可以确保覆盖所有情况。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 sealed class Result { data class Success (val data : String) : Result() data class Error (val message: String) : Result() object Loading : Result() } fun handleResult (result: Result ) { when (result) { is Result.Success -> println("成功:${result.data} " ) is Result.Error -> println("错误:${result.message} " ) Result.Loading -> println("加载中..." ) } }
7.3 abstract关键字(抽象类) abstract关键字用于修饰类、属性、方法,表明它们必须被继承、重写或实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 abstract class Shape { abstract val area: Double abstract fun draw () fun display () { println("Displaying shape" ) } } class Circle (val radius: Double ) : Shape() { override val area: Double get () = Math.PI * radius * radius override fun draw () { println("Drawing circle with radius $radius " ) } }
7.4 data关键字(数据类) data关键字用于修饰类,表明它是一个数据类,用于存储数据。编译器会自动生成以下方法:
equals() / hashCode()toString()copy()componentN()(用于解构声明)1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 data class User (val name: String, val age: Int , val city: String)fun main () { val user1 = User("张三" , 18 , "北京" ) val user2 = User("张三" , 18 , "北京" ) println(user1 == user2) println(user1) val user3 = user1.copy(age = 20 ) println(user3) val (name, age, city) = user1 println("$name , $age , $city " ) }
7.5 接口(interface) 接口使用interface关键字声明,可以定义抽象方法和默认实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 interface Clickable { fun click () fun show () { println("Showing clickable item" ) } } class Button : Clickable { override fun click () { println("Button clicked" ) } } interface Draggable { fun drag () } class ImageButton : Clickable , Draggable { override fun click () { println("Image button clicked" ) } override fun drag () { println("Dragging image button" ) } }
接口的优势:
多实现 :一个类可以实现多个接口解耦代码 :接口可以将代码解耦,使代码更灵活、可维护定义规范 :接口可以定义一组方法规范7.6 by关键字(委托) by关键字用于实现接口的委托,将接口的实现委托给另一个对象,避免重复实现接口方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 interface Printer { fun print (message: String ) } class ConsolePrinter : Printer { override fun print (message: String ) { println(message) } } class LogPrinter (private val printer: Printer) : Printer by printer { override fun print (message: String ) { printer.print("[LOG] $message " ) } } fun main () { val consolePrinter = ConsolePrinter() val logPrinter = LogPrinter(consolePrinter) logPrinter.print("Hello" ) }
by关键字的常见用法:
1 2 3 4 5 6 7 8 9 val userName: String by lazy { println("执行初始化逻辑" ) "张三" }
by关键字的优势:
代码复用 :将接口实现委托给另一个对象灵活切换 :可以动态地切换委托对象减少代码量 :避免重复实现接口方法7.7 with关键字 with关键字用于在一个对象的作用域内执行代码,避免重复引用对象。
核心作用: 给一段代码块指定一个上下文对象,在代码块里直接访问这个对象的属性/方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 data class User (var name: String, var age: Int , var city: String)fun main () { val user = User("张三" , 18 , "北京" ) user.name = "李四" user.age = 20 user.city = "上海" println("姓名:${user.name} ,年龄:${user.age} ,城市:${user.city} " ) with(user) { name = "王五" age = 22 city = "广州" println("姓名:$name ,年龄:$age ,城市:$city " ) } }
with关键字的优势:
减少代码量 :避免重复引用对象提高可读性 :将代码块内的代码与对象关联起来方便调用 :可以方便地调用对象的方法八、集合 8.1 不可变集合 Kotlin区分可变集合和不可变集合,不可变集合只能读取,不能修改。
1 2 3 4 5 6 7 8 val list = listOf(1 , 2 , 3 , 4 , 5 )val set = setOf(1 , 2 , 3 , 2 , 1 ) val map = mapOf("a" to 1 , "b" to 2 , "c" to 3 )
Set集合的特点:
元素唯一:不允许重复元素 无序:和List的「有序、可重复」形成核心区别 8.2 可变集合 可变集合可以动态地添加、删除、修改元素。
1 2 3 4 5 6 7 8 9 10 11 12 val mutableList = mutableListOf(1 , 2 , 3 )mutableList.add(4 ) mutableList.removeAt(0 ) val mutableSet = mutableSetOf(1 , 2 , 3 )mutableSet.add(4 ) val mutableMap = mutableMapOf("a" to 1 )mutableMap["b" ] = 2
8.3 mutableListOf vs arrayListOf 1 2 3 4 5 val list1 = mutableListOf(1 , 2 , 3 )val list2 = arrayListOf(1 , 2 , 3 )
推荐使用: mutableListOf(),因为它面向接口编程,更加灵活。
8.4 集合遍历 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 data class User (val name: String, val age: Int , val city: String)fun main () { val users = mutableListOf( User("张三" , 18 , "北京" ), User("李四" , 20 , "上海" ), User("王五" , 22 , "广州" ) ) for (user in users) { println("姓名:${user.name} ,年龄:${user.age} ,城市:${user.city} " ) } with(users) { for (user in this ) { println("姓名:${user.name} ,年龄:${user.age} ,城市:${user.city} " ) } } users.forEach { user -> println("姓名:${user.name} ,年龄:${user.age} ,城市:${user.city} " ) } }
8.5 Map集合 Map集合用于存储键值对,每个键都是唯一的。
Map集合的优势 方便存储键值对 :可以方便地存储键值对,实现快速的查找和访问方便遍历 :可以方便地遍历键值对,实现对集合中元素的操作动态管理 :可以方便地添加、删除、修改键值对1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 fun main () { val map = mapOf("a" to 1 , "b" to 2 , "c" to 3 ) println(map["a" ]) val firstPair = map.entries.first() println("第一个键值对:$firstPair " ) for ((key, value) in map) { println("$key -> $value " ) } }
字符串处理 1 2 3 4 5 6 7 8 9 10 fun main () { val str = "hello" val upperStr = str.uppercase() println(upperStr) val lowerStr = "HELLO" .lowercase() println(lowerStr) }
8.6 数组常用操作 Kotlin为数组提供了丰富的操作方法。
数组创建 1 2 3 4 5 6 7 8 val intArr = IntArray(5 ) val strArr = arrayOf("苹果" , "香蕉" )val arr = arrayOf(10 , 20 , 30 , 40 , 400 )
常用属性和函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 fun main () { val arr = arrayOf(10 , 20 , 30 , 40 , 400 ) println("长度:${arr.size} " ) println("是否为空:${arr.isEmpty()} " ) println("包含 20:${arr.contains(20 )} " ) println("最大值:${arr.maxOrNull()} " ) println("最小值:${arr.minOrNull()} " ) println("求和:${arr.sum()} " ) println("平均值:${arr.average()} " ) println("元素个数:${arr.count()} " ) }
8.7 集合过滤操作 Kotlin提供了强大的过滤功能,可以根据条件筛选集合元素。
filter系列方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 fun main () { val arr = arrayOf(10 , 20 , 30 , 40 , 400 ) println("过滤大于 30 的元素:${arr.filter { it > 30 } }" ) println("过滤索引为偶数的元素:${arr.filterIndexed { index, _ -> index % 2 == 0 } }" ) println("过滤不是偶数的元素:${arr.filterNot { it % 2 == 0 } }" ) val mixedArr = arrayOf(1 , "Hello" , 3.14 , true , 5 ) println("过滤Int类型元素:${mixedArr.filterIsInstance<Int>()} " ) }
map映射操作 1 2 3 4 5 6 7 8 9 10 11 fun main () { val arr = arrayOf(10 , 20 , 30 , 40 , 400 ) println("映射每个元素为其平方:${arr.map { it * it } }" ) println("映射为索引和值的组合:${arr.mapIndexed { index, value -> "[$index ]=$value " } }" ) }
8.8 集合分区与分组 partition方法 partition()方法用于将列表根据指定条件分为两个列表。
1 2 3 4 5 6 7 8 fun main () { val arr = arrayOf(10 , 20 , 30 , 40 , 400 ) val (even, odd) = arr.partition { it % 2 == 0 } println("偶数列表:$even " ) println("奇数列表:$odd " ) }
groupBy方法 groupBy()方法用于将列表根据指定条件分组。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 fun main () { val numbers = listOf(10 , 20 , 30 , 40 , 400 ) val groupedMap = numbers.groupBy { it % 2 == 0 } println(groupedMap) val words = listOf("apple" , "bat" , "cat" , "dog" , "elephant" ) val byLength = words.groupBy { it.length } println(byLength) }
8.9 集合条件判断 any、all、none是Kotlin集合中判断元素是否满足条件的核心函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 fun main () { val numbers = listOf(10 , 20 , 30 , 40 , 400 ) val hasEndWith0 = numbers.any { it.toString().endsWith("0" ) } println("是否有以0结尾的数字:$hasEndWith0 " ) val allPositive = numbers.all { it > 0 } println("是否所有元素都大于0:$allPositive " ) val noneGreaterThan30 = numbers.none { it > 30 } println("是否没有元素大于30:$noneGreaterThan30 " ) }
8.10 集合连接与展开 joinToString方法 joinToString()方法用于将集合元素连接成字符串。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 fun main () { val arr = arrayOf(10 , 20 , 30 , 40 , 400 ) println("连接每个元素:${arr.joinToString()} " ) println("连接每个元素为逗号分隔:${arr.joinToString("," )} " ) println("连接每个元素为空格分隔:${arr.joinToString(" " )} " ) println(arr.joinToString(", " , "[" , "]" ) { "num=$it " }) }
flatten方法 flatten()方法用于将嵌套的列表展开为一个列表。
1 2 3 4 5 fun main () { val nestedList = listOf(listOf(1 , 2 , 3 ), listOf(4 , 5 , 6 )) val flattenedList = nestedList.flatten() println(flattenedList) }
8.11 集合切片与截取 slice方法 slice()方法用于获取列表中指定索引范围内的元素。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 fun main () { val arr = arrayOf(10 , 20 , 30 , 40 , 400 ) println("索引1到3的元素:${arr.slice(1. .3 )} " ) println("索引1到3,步长为2:${arr.slice(1. .3 step 2 )} " ) println("指定索引的元素:${arr.slice(listOf(0 , 2 , 4 ))} " ) }
take和drop系列方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 fun main () { val arr = arrayOf(10 , 20 , 30 , 40 , 400 ) val firstThree = arr.take(3 ) println("前3个元素:$firstThree " ) val lastThree = arr.takeLast(3 ) println("后3个元素:$lastThree " ) val droppedList = arr.drop(2 ) println("丢弃前2个元素:$droppedList " ) val droppedLastList = arr.dropLast(2 ) println("丢弃后2个元素:$droppedLastList " ) }
takeWhile和dropWhile方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 fun main () { val arr = arrayOf(10 , 20 , 30 , 40 , 400 ) val takenList = arr.takeWhile { it < 30 } println("获取小于30的元素:$takenList " ) val droppedList = arr.dropWhile { it < 30 } println("丢弃小于30的元素:$droppedList " ) val takenLastList = arr.takeLastWhile { it > 30 } println("获取大于30的后N个元素:$takenLastList " ) val droppedLastList = arr.dropLastWhile { it > 30 } println("丢弃大于30的后N个元素:$droppedLastList " ) }
8.12 集合转换与分块 toList方法 toList()方法用于将范围或其他集合转换为列表。
1 2 3 4 5 fun main () { val list = (10. .20 ).toList() println(list) }
chunked方法 chunked()方法用于将列表分为指定大小的子列表。
1 2 3 4 5 6 7 8 9 10 11 fun main () { val list = (1. .10 ).toList() val chunkedList = list.chunked(3 ) println(chunkedList) val sumList = list.chunked(3 ) { it.sum() } println(sumList) }
windowed方法 windowed()方法用于将列表分为指定大小的滑动窗口。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 fun main () { val list = (1. .10 ).toList() val windowedList = list.windowed(3 ) println(windowedList) val sumWindow = list.windowed(3 ) { it.sum() } println(sumWindow) val steppedWindow = list.windowed(3 , step = 2 ) println(steppedWindow) }
8.13 集合元素获取 elementAt系列方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 fun main () { val list = listOf(10 , 20 , 30 , 40 , 400 ) val thirdElement = list.elementAt(2 ) println("索引2的元素:$thirdElement " ) val fifthElement = list.elementAtOrNull(4 ) println("索引4的元素:$fifthElement " ) val outOfBound = list.elementAtOrNull(10 ) println("索引10的元素:$outOfBound " ) val seventhElement = list.elementAtOrElse(6 ) { -1 } println("索引6的元素:$seventhElement " ) }
random方法 random()方法用于获取集合中的随机元素。
1 2 3 4 5 6 7 8 9 10 11 fun main () { val list = listOf(10 , 20 , 30 , 40 , 400 ) val randomElement = list.random() println("随机元素:$randomElement " ) val randomWithSeed = list.random(java.util.Random(42 )) println("带种子的随机元素:$randomWithSeed " ) }
8.14 集合统计与聚合 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 fun main () { val list = listOf(10 , 20 , 30 , 40 , 400 ) val isEmpty = list.isEmpty() println("是否为空:$isEmpty " ) val sum = list.sum() println("总和:$sum " ) val count = list.count { it > 100 } println("大于100的元素数量:$count " ) val average = list.average() println("平均值:$average " ) val max = list.maxOrNull() println("最大值:$max " ) val min = list.minOrNull() println("最小值:$min " ) val sumOf = list.sumOf { it.toDouble() } println("sumOf结果:$sumOf " ) }
8.15 集合排序 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 fun main () { val list = listOf(400 , 10 , 30 , 40 , 20 ) val sortedList = list.sorted() println("升序排序:$sortedList " ) val sortedDescendingList = list.sortedDescending() println("降序排序:$sortedDescendingList " ) val sortedByList = list.sortedBy { it % 10 } println("按个位数排序:$sortedByList " ) val sortedByDescList = list.sortedByDescending { it % 10 } println("按个位数降序:$sortedByDescList " ) val sortedWithList = list.sortedWith(compareBy { it % 100 }) println("使用比较器排序:$sortedWithList " ) val customSorted = list.sortedWith { a, b -> when { a % 10 < b % 10 -> -1 a % 10 > b % 10 -> 1 else -> 0 } } println("自定义排序:$customSorted " ) }
8.16 集合操作总结表 操作类型 方法 说明 过滤 filter过滤满足条件的元素 filterIndexed带索引的过滤 filterNot过滤不满足条件的元素 filterIsInstance过滤指定类型的元素 映射 map将元素映射为新值 mapIndexed带索引的映射 分区 partition分为两个列表 groupBy按条件分组 判断 any是否存在满足条件的元素 all是否所有元素都满足条件 none是否没有元素满足条件 截取 take获取前N个元素 takeLast获取后N个元素 drop丢弃前N个元素 dropLast丢弃后N个元素 排序 sorted升序排序 sortedDescending降序排序 sortedBy按指定函数排序 统计 sum求和 average平均值 maxOrNull最大值 minOrNull最小值 count计数
8.17 集合高级排序 compareByDescending方法 1 2 3 4 5 6 7 fun main () { val list = listOf(10 , 20 , 30 , 40 , 400 ) val sortedWithList = list.sortedWith(compareByDescending { it % 10 }) println(sortedWithList) }
thenBy方法 thenBy()方法用于对已排序的列表进行二级排序(secondary排序)。
1 2 3 4 5 6 7 8 9 10 11 fun main () { val list = listOf(10 , 20 , 30 , 40 , 400 ) val thenByList = list.sortedWith(compareBy<Int > { it % 10 }.thenBy { it }) println(thenByList) val thenByDescList = list.sortedWith(compareByDescending<Int > { it % 10 }.thenBy { it }) println(thenByDescList) }
8.18 集合查找 binarySearch方法 binarySearch()方法用于对已排序的列表进行二分查找,效率比线性查找高很多。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 fun main () { val list = listOf(10 , 20 , 30 , 40 , 400 ) val binarySearch = list.binarySearch(30 ) println("30的索引:$binarySearch " ) val notFound = list.binarySearch(25 ) println("25的索引:$notFound " ) val rangeSearch = list.binarySearch(30 , 0 , 3 ) println("范围内查找30:$rangeSearch " ) }
注意: 二分查找要求数组必须是有序的!
8.19 Map集合详解 Map集合的创建方式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 fun main () { val immutableMap = mapOf(1 to "张三" , 2 to "李四" , 3 to "王五" ) println(immutableMap) val mutableMap = mutableMapOf(1 to "张三" , 2 to "李四" ) mutableMap[3 ] = "王五" mutableMap[1 ] = "赵六" println(mutableMap) val hashMap = hashMapOf(1 to "张三" , 2 to "李四" ) println(hashMap) }
mutableMapOf vs hashMapOf 方法 返回类型 底层实现 使用场景 mutableMapOf()MutableMap(接口) Java HashMap 99%的Kotlin原生代码 hashMapOf()java.util.HashMap(类) Java HashMap 与Java互操作、需要HashMap独有方法
to关键字 to关键字用于创建键值对,将键和值组合成一个Pair对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 fun main () { val map = mapOf< Int , String>(1 to "张三" , 2 to "李四" , 3 to "王五" ) val pair = 1 to "张三" println(pair) map.forEach { (key, value) -> println("键:$key ,值:$value " ) } for ((key, value) in map) { println("键:$key ,值:$value " ) } }
8.20 集合遍历方式总结 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 data class User (val name: String, val age: Int , val city: String)fun main () { val users = mutableListOf( User("张三" , 18 , "北京" ), User("李四" , 20 , "上海" ), User("王五" , 22 , "广州" ) ) for (user in users) { println("姓名:${user.name} ,年龄:${user.age} ,城市:${user.city} " ) } with(users) { for (user in this ) { println("姓名:${user.name} ,年龄:${user.age} ,城市:${user.city} " ) } } users.forEach { println("姓名:${it.name} ,年龄:${it.age} ,城市:${it.city} " ) } users.forEach { user -> println("姓名:${user.name} ,年龄:${user.age} ,城市:${user.city} " ) } users.forEachIndexed { index, user -> println("索引:$index ,姓名:${user.name} " ) } }
十、类型转换与泛型 10.1 as关键字 as关键字用于将对象转换为指定的类型。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 fun main () { val intList = listOf(1 , 2 , 3 ) val anyList: List<Any> = intList println(anyList) val obj: Any = "Hello" val str: String = obj as String println(str) val obj2: Any = 123 val str2: String? = obj2 as ? String println(str2) if (obj is String) { println(obj.length) } }
10.2 泛型out(协变) 泛型out用于表示只能从泛型类型中读取值,不能写入值。这称为协变(Covariance)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 fun readFromList (list: MutableList <out Number >) { val num: Number = list[0 ] println(num) } fun main () { val intList = mutableListOf(1 , 2 , 3 ) readFromList(intList) }
协变的作用: 允许将MutableList<Int>赋值给MutableList<out Number>,因为只能读取,不会破坏类型安全。
10.3 泛型in(逆变) 泛型in用于表示只能将值写入泛型类型,不能从泛型类型中读取值。这称为逆变(Contravariance)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 fun writeToList (list: MutableList <in Number >) { list.add(10 ) list.add(3.14 ) val item: Any? = list[0 ] println(item) } fun main () { val anyList = mutableListOf<Any>() writeToList(anyList) println(anyList) }
逆变的作用: 允许将MutableList<Any>赋值给MutableList<in Number>,因为只能写入Number及其子类,不会破坏类型安全。
10.4 泛型类型约束总结 关键字 名称 方向 使用场景 out T协变 只能读取(生产者) 当你只需要从集合中读取数据时 in T逆变 只能写入(消费者) 当你只需要向集合中写入数据时 T不变 可读可写 当你需要同时读写数据时
记忆口诀:
out = 输出 = 读取 = 生产者in = 输入 = 写入 = 消费者10.5 where子句 where子句用于限制泛型类型的范围,可以指定多个约束条件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 fun <T : Number> sum (a: T , b: T ) : Double { return a.toDouble() + b.toDouble() } fun <T> process (value: T ) where T : Number, T : Comparable<T> { println("值:$value " ) println("比较:${value.compareTo(value)} " ) } class Calculator <T > where T : Number , T : Comparable <T > { fun max (a: T , b: T ) : T { return if (a > b) a else b } } fun main () { println(sum(10 , 20 )) println(sum(3.14 , 2.86 )) val calc = Calculator<Int >() println("最大值:${calc.max(10 , 20 )} " ) }
十一、inline函数 11.1 inline函数基础 inline(内联)函数是一个性能优化关键字,核心作用是:把函数的代码直接”复制粘贴”到调用处,而非传统的函数调用。
普通函数调用过程 当你调用一个普通函数时,JVM会做这些事:
跳转到函数的内存地址 执行函数代码 执行完跳回调用处 这个”跳转”过程有微小的性能开销(尤其是函数体很短、调用次数极多的时候)。
inline函数的优势 给函数加inline关键字后,编译器会在编译阶段:
把函数的全部代码直接复制到调用的地方 没有函数跳转,直接执行代码 特别适合lambda表达式: 因为lambda本质是匿名类对象,每次调用都会创建临时对象,带来额外开销;而inline会把lambda的代码也一起内联,消除lambda的对象创建开销。
11.2 inline函数示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 fun calculate (a: Int , b: Int , op: (Int , Int ) -> Int ) : Int { return op(a, b) } inline fun inlineCalculate (a: Int , b: Int , op: (Int , Int ) -> Int ) : Int { return op(a, b) } fun main () { val result1 = calculate(10 , 20 ) { x, y -> x + y } println(result1) val result2 = inlineCalculate(10 , 20 ) { x, y -> x + y } println(result2) }
11.3 inline函数的实际应用 Kotlin标准库中大量使用了inline函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 inline fun <T> mutableListOf (vararg elements: T ) : MutableList<T> { return ArrayList(elements.asList()) } inline fun <T> Iterable<T> .forEach (action: (T ) -> Unit ) : Unit { for (element in this ) action(element) } fun main () { val list = mutableListOf(1 , 2 , 3 , 4 , 5 ) list.forEach { println(it * 2 ) } }
11.4 inline函数使用建议 适合使用inline的场景:
函数体很短 函数接收lambda参数 函数被频繁调用 不适合使用inline的场景:
函数体很长(会导致代码膨胀) 函数是递归函数 函数没有lambda参数且函数体较复杂 11.5 noinline和crossinline 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 inline fun mixedInline ( a: Int , inlineOp: (Int ) -> Int , noinline noInlineOp: (Int ) -> Int ) : Int { return noInlineOp(inlineOp(a)) } inline fun crossinlineExample (crossinline action: () -> Unit ) { Runnable { action() }.run() } fun main () { val result = mixedInline(10 , { it * 2 }, { it + 10 }) println(result) }
十二、lambda表达式 12.1 lambda表达式基础 12.1.1 什么是lambda表达式 lambda表达式是一种匿名函数,它可以作为参数传递给其他函数或存储在变量中。
12.1.2 lambda表达式的语法 1 2 3 4 5 6 7 8 9 10 11 12 13 val add: (Int , Int ) -> Int = { a, b -> a + b }val add2: (Int , Int ) -> Int = { a, b -> a + b }val double: (Int ) -> Int = { it * 2 }val printHello: () -> Unit = { println("Hello!" ) }val mylambda= { a : Int -> println(a) }
12.1.3 apply函数 apply函数是一个作用域函数,它可以在对象上执行一系列操作并返回该对象本身。 与with函数不同,apply函数不返回lambda表达式的结果,而是返回对象本身。
1 2 3 4 5 6 val person = Person().apply { name = "张三" age = 30 address = "中国" }
12.1.4 also函数 also 和 apply 都是用于简化对象操作的作用域函数,核心都是让你在不重复写对象名的前提下对对象进行操作
apply:对象初始化的 “专属工具” apply 的上下文是 this(可以省略),非常适合给对象设置属性、调用初始化方法,写完后返回原对象,是 Kotlin 中初始化对象最常用的函数。 also 的上下文是 it(必须显式写,除非用不到),适合在不修改对象内部属性的前提下,对对象执行附加操作(比如打印日志、校验、存入集合、传参等)。
1 2 3 4 5 6 val person = Person().also { it.name = "张三" it.age = 30 it.address = "中国" }
12.1.5 let函数 let 同样是核心的作用域函数,和你刚了解的 also/apply 相比,它的核心特征是改变返回值 + 用 it 引用对象. 空安全处理(最常用场景)结合 ?. 操作符,let 可以优雅地处理 “对象非空时才执行操作” 的逻辑,避免繁琐的 if (obj != null) 判断.
1 2 3 4 5 6 7 val person = Person().let { it.name = "张三" it.age = 30 it.address = "中国" it }
12.1.6 thread线程 thread 是 Kotlin 标准库中用于创建和启动线程的函数。它可以在后台执行耗时操作,避免阻塞主线程。
线程依赖包导入 dependencies { implementation(“org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4”) }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 thread { println("后台线程执行中" ) } Thread.sleep(1000 ) Thread.currentThread().name val parentJob = coroutineScope(default).launch { delay(1000 ) println("子协程执行中" ) launch { println(Thread.currentThread().name) println("子子协程执行中" ) } } parentJob.join()
12.1.7 System // 测量代码执行时间 val start = System.currentTimeMillis()
async 是 Kotlin 标准库中用于创建和启动异步任务的函数。它可以在后台执行耗时操作,避免阻塞主线程。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 val deferredResult = async { delay(1000 ) return @async "异步任务完成" } val result = deferredResult.await()println(result) globalScope.launch { delay(1000 ) println("子协程执行中" ) } withTimeoutOrNull(1000 ) { delay(2000 ) println("子协程执行中" ) } runBlocking { delay(1000 ) println("子协程执行中" ) } CoroutineExceptionHandler 是 Kotlin 标准库中用于处理协程异常的类。它可以在协程中捕获异常并进行处理,避免异常导致程序崩溃。 ```kotlin val exceptionHandler = CoroutineExceptionHandler { _, exception -> println("捕获到协程异常:$exception " ) } val job = coroutineScope(default).launch(exceptionHandler) { throw Exception("模拟异常" ) } job.join() invoke 是 Kotlin 标准库中用于调用函数的函数。它可以在 lambda 表达式中调用其他函数,也可以在协程中调用其他函数。 ```kotlin fun sayHello (name: String ) { println("Hello, $name !" ) } val lambda = { name: String -> sayHello(name) }lambda.invoke("张三" ) coroutineScope(default).launch { sayHello("李四" ) } invokeOnCompletion 是 Kotlin 标准库中用于在协程完成时调用的函数。它可以在协程中注册一个回调函数,当协程完成时(无论是否异常),都会调用该回调函数。 ```kotlin val job = coroutineScope(default).launch { delay(1000 ) println("子协程执行中" ) } job.invokeOnCompletion { exception -> if (exception == null ) { println("协程执行完成" ) } else { println("协程执行异常:$exception " ) } } job.join() withContext 是 Kotlin 标准库中用于切换协程上下文的函数。它可以在协程中切换到不同的线程池或上下文,以执行耗时操作。 ```kotlin val job = coroutineScope(default).launch { delay(1000 ) println("子协程执行中" ) } withContext(Dispatchers.IO) { delay(1000 ) println("子协程执行中" ) } job.join() suspend 是 Kotlin 标准库中用于标记挂起函数的关键字。挂起函数可以在协程中暂停执行,等待异步操作完成后继续执行。```kotlin suspend fun doSomethingAsync () : String { delay(1000 ) return "异步操作完成" } coroutineScope(default).launch { val result = doSomethingAsync() println(result) } cancel 是 Kotlin 标准库中用于取消协程的函数。它可以在协程中调用,以取消正在执行的操作。 ```kotlin val job = coroutineScope(default).launch { delay(1000 ) println("子协程执行中" ) } job.cancel() job.join()
十三、总结 本教程涵盖了Kotlin的核心基础知识,包括:
基础语法 :变量声明、数据类型、空安全函数 :参数默认值、可变参数控制流 :循环、条件判断、when表达式面向对象 :类、构造函数、继承、接口、抽象类高级特性 :单例、委托、延迟初始化、数据类集合操作 :可变集合与不可变集合、过滤、映射、排序、统计等类型转换与泛型 :as关键字、泛型协变逆变、where子句性能优化 :inline函数、noinline、crossinline集合操作 :可变列表、不可变列表、数组、映射、集合操作符异常处理 :try-catch-finally、异常类型、自定义异常文件操作 :文件读取、写入、删除、遍历目录并发编程 :线程、线程池、协程、通道、流数据库操作 :JDBC、Room数据库、Kotlin协程数据库操作Kotlin是一门现代化的编程语言,具有简洁、安全、互操作性强等特点。掌握这些基础知识后,你可以进一步学习Kotlin的高级特性,如协程、扩展函数、高阶函数等。
希望本教程对你有所帮助!如有问题,欢迎交流讨论。