1. Kotlin函数全解析:从基础到高阶实战
1.1 函数定义与两种形式
在Kotlin中,函数定义使用fun关键字,基本语法结构如下:
kotlin复制fun 函数名(参数名: 参数类型): 返回值类型 {
// 函数体
}
Kotlin函数主要分为两种形式:
表达式体函数(Expression-body)
kotlin复制fun add(a: Int, b: Int): Int = a + b
// 可进一步简化为:
fun add(a: Int, b: Int) = a + b // 类型推断
注意:表达式体函数必须能在一行内完成逻辑,且返回值类型可省略(编译器能推断时)
代码块体函数(Block-body)
kotlin复制fun printSum(a: Int, b: Int): Unit { // Unit返回类型可省略
println("Sum is ${a + b}")
}
实际开发中选择建议:
- 简单计算、转换操作优先用表达式体
- 需要多步操作或有副作用的用代码块体
- 团队统一风格更重要
1.2 参数传递的实用技巧
Kotlin支持多种参数传递方式:
默认参数(避免Java的重载写法)
kotlin复制fun greet(name: String = "Guest", prefix: String = "Hello") {
println("$prefix, $name!")
}
greet() // 输出: Hello, Guest!
greet("Alice", "Hi") // 输出: Hi, Alice!
命名参数(提高可读性)
kotlin复制greet(prefix = "Hey", name = "Bob") // 参数顺序可调
可变参数(vararg)
kotlin复制fun printAll(vararg messages: String) {
for (msg in messages) println(msg)
}
printAll("Hello", "Kotlin", "World") // 可传任意数量参数
避坑指南:当vararg不是最后一个参数时,命名参数能解决歧义:
kotlin复制fun tricky(vararg nums: Int, flag: Boolean) {...} tricky(1, 2, 3, flag = true) // 必须用命名参数指定flag
1.3 Lambda表达式深度应用
Lambda的本质是匿名函数,典型结构:
kotlin复制{ 参数 -> 函数体 }
实战案例1:集合操作
kotlin复制val numbers = listOf(1, 2, 3, 4)
val doubled = numbers.map { it * 2 } // it是单个参数的隐式名称
val evens = numbers.filter { num -> num % 2 == 0 }
实战案例2:事件回调
kotlin复制button.setOnClickListener { view ->
Toast.makeText(context, "Clicked!", Toast.LENGTH_SHORT).show()
}
Lambda简化规则:
- 参数类型可推断时可省略
- 单参数可用
it代替 - 最后参数是Lambda时可移出括号外
- 唯一参数是Lambda时可省略括号
1.4 高阶函数开发模式
高阶函数是指以函数为参数或返回值的函数。典型应用场景:
回调封装
kotlin复制fun doAsync(callback: (Result) -> Unit) {
thread {
// 模拟耗时操作
val result = heavyWork()
runOnUiThread { callback(result) }
}
}
// 使用
doAsync { result ->
updateUI(result)
}
函数工厂
kotlin复制fun createMultiplier(factor: Int): (Int) -> Int {
return { number -> number * factor }
}
val triple = createMultiplier(3)
println(triple(5)) // 输出15
DSL构建
kotlin复制fun table(init: TableBuilder.() -> Unit): Table {
val builder = TableBuilder()
builder.init()
return builder.build()
}
// 使用
table {
tr {
td { "Name" }
td { "Age" }
}
}
性能提示:高频调用的高阶函数应使用
inline修饰符避免运行时开销
2. Kotlin类与对象实战指南
2.1 类定义与构造最佳实践
Kotlin类的基本结构:
kotlin复制class Person(val name: String, var age: Int) {
// 类体
}
构造方法技巧:
- 主构造简洁:只声明必需属性
- 次构造处理复杂情况:
kotlin复制class User {
val id: String
var name: String
constructor(id: String) {
this.id = id
this.name = "Unknown"
}
constructor(id: String, name: String) {
this.id = id
this.name = name
}
}
- Init块的正确使用场景:
kotlin复制class DatabaseClient(url: String) {
init {
require(url.isNotBlank()) { "URL不能为空" }
}
val connection: Connection = createConnection(url)
}
2.2 空安全操作全方案
Kotlin的空安全体系:
安全调用链
kotlin复制val length = user?.address?.street?.length
Elvis运算符的妙用
kotlin复制val displayName = user.name ?: "Anonymous"
val maxWidth = config.maxWidth?.takeIf { it > 0 } ?: 100
类型安全转换
kotlin复制val obj: Any = "Hello"
val str: String? = obj as? String // 失败返回null而非异常
let作用域函数
kotlin复制user?.let {
println("Processing ${it.name}")
saveToDb(it)
}
重要原则:尽量避免使用
!!非空断言,除非你100%确定不为null
2.3 可见性控制策略
Kotlin的可见性修饰符:
| 修饰符 | 类成员 | 顶层声明 |
|---|---|---|
| public | 所有可见 | 所有可见 |
| internal | 模块内可见 | 模块内可见 |
| protected | 子类可见 | 不可用 |
| private | 类内部可见 | 文件内可见 |
模块化设计建议:
- 默认使用
public暴露最小接口 - 实现细节用
internal限制模块内访问 - 工具函数用
private限制文件作用域 - 避免过度使用
protected(考虑组合优于继承)
2.4 类成员高级特性
延迟初始化
kotlin复制class MyService {
lateinit var dependency: Dependency
fun init() {
dependency = Dependency()
}
fun action() {
check(::dependency.isInitialized) { "未初始化" }
dependency.doSomething()
}
}
属性委托
kotlin复制class Preferences(context: Context) {
var token by Delegates.preferences(context, "")
var lastLogin by Delegates.preferences(context, 0L)
}
伴生对象(替代Java静态成员)
kotlin复制class Logger {
companion object {
private const val TAG = "App"
fun debug(message: String) {
Log.d(TAG, message)
}
}
}
// 使用
Logger.debug("Startup complete")
3. Kotlin函数式编程实战
3.1 集合操作性能优化
序列(Sequence)的惰性求值
kotlin复制val result = listOf(1, 2, 3, 4)
.asSequence() // 转换为序列
.map { it * 2 } // 中间操作
.filter { it > 4 } // 中间操作
.toList() // 终端操作
性能对比:大数据集(万级以上)使用Sequence可显著减少中间集合创建
常用终端操作:
toList()/toSet()first()/last()count()fold()/reduce()any()/all()/none()
3.2 作用域函数选择指南
Kotlin的五大作用域函数:
| 函数 | 上下文对象 | 返回值 | 适用场景 |
|---|---|---|---|
| let | it | Lambda结果 | 空检查/转换 |
| run | this | Lambda结果 | 对象配置/计算 |
| with | this | Lambda结果 | 对已有对象操作 |
| apply | this | 对象本身 | 对象初始化 |
| also | it | 对象本身 | 附加效果/日志记录 |
典型应用场景:
kotlin复制// let - 安全转换
val length = nullableString?.let {
it.trim().length
} ?: 0
// apply - 对象构建
val dialog = AlertDialog.Builder(context).apply {
setTitle("提示")
setMessage("确定删除吗?")
setPositiveButton("确定") { _, _ -> }
setNegativeButton("取消", null)
}.create()
// run - 计算属性
val displayText = run {
val now = System.currentTimeMillis()
"Current time: ${SimpleDateFormat("HH:mm").format(now)}"
}
3.3 内联函数原理与实现
inline原理:
kotlin复制inline fun <T> lock(lock: Lock, body: () -> T): T {
lock.lock()
try {
return body()
} finally {
lock.unlock()
}
}
// 编译后相当于:
lock.lock()
try {
// 直接插入Lambda代码
} finally {
lock.unlock()
}
使用场景:
- 高阶函数(减少函数对象创建)
- 类型参数具体化(reified)
kotlin复制inline fun <reified T> parseJson(json: String): T {
return Gson().fromJson(json, T::class.java)
}
val user = parseJson<User>(jsonStr) // 直接获取具体类型
注意事项:
- 大Lambda慎用inline(会导致代码膨胀)
- 递归函数不能inline
- 公有API谨慎使用(影响二进制兼容性)
4. Kotlin与Java互操作实践
4.1 空安全类型映射
Java类型在Kotlin中的对应:
| Java类型 | Kotlin类型 |
|---|---|
@Nullable String |
String? |
@NotNull String |
String |
| 无注解类型 | 平台类型(String!) |
处理建议:
- 添加
@Nullable/@NotNull注解 - 对平台类型立即转换:
kotlin复制val javaObj = JavaClass()
val name: String = javaObj.name ?: "default" // 明确处理null
4.2 函数式接口兼容
Java函数式接口在Kotlin中的使用:
kotlin复制// Java
public interface OnClickListener {
void onClick(View v);
}
// Kotlin使用
view.setOnClickListener { println("Clicked") }
特殊处理SAM转换:
kotlin复制val runnable = Runnable { println("Running") }
// 需要显式SAM转换的场景
val executor = Executors.newSingleThreadExecutor()
executor.execute(Runnable { println("Task") }) // 必须明确Runnable
4.3 扩展方法的Java调用
Kotlin扩展方法在Java中的表现:
kotlin复制// StringExtensions.kt
fun String.addExclamation(): String = "$this!"
// Java调用
String result = StringExtensionsKt.addExclamation("Hello");
优化Java调用体验:
- 使用
@file:JvmName注解修改生成类名
kotlin复制@file:JvmName("StringUtils")
package com.example
fun String.addExclamation(): String = "$this!"
- 添加
@JvmOverloads处理默认参数
kotlin复制@JvmOverloads
fun joinToString(collection: Collection<String>, separator: String = ", ") { ... }
4.4 属性访问差异处理
Java访问Kotlin属性:
kotlin复制class User(val name: String, var age: Int)
// Java中
User user = new User("Alice", 25);
String name = user.getName(); // val生成getter
user.setAge(26); // var生成setter
特殊案例处理:
- 禁用getter/setter生成:
kotlin复制@JvmField
val id: String = UUID.randomUUID().toString()
- 属性名与Java关键字冲突:
kotlin复制val `when`: String = "time" // 反引号转义
掌握这些互操作技巧可以显著提升混合代码库的开发效率,特别是在Android和Spring等Java生态中的Kotlin应用。