# 成为 Kotlin 超人 > 来到这里,我不再会给出详尽的用法。
> 以你的实力,只要我指出在什么时候应该使用什么就够了。 ## 在哪里找到最全面的 Kotlin 文档 虽然 [深入 Kotlin](./深入Kotlin.md) 中已经讲了很多内容,但其实我仍有删减,比如生成随机数相关的内容。 [官方文档](https://book.kotlincn.net/text/d-concepts.html) ## JSON 序列化 Kotlin-serialization 是最佳选择,它需要加载一个 gradle 插件,注意要与你的 Kotlin 版本一致: ```kotlin plugins { kotlin("jvm") version "2.3.20" kotlin("plugin.serialization") version "2.3.20" } ``` 还有一个依赖 ```kotlin implementation("org.jetbrains.kotlin:kotlin-reflect") ``` ## Kotlin 协程与多线程细节 核心依赖: ```kotlin dependencies { implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1") } ``` 要点概括: - **不要用 `GlobalScope`**:建议自定义 `CoroutineScope(SupervisorJob() + Dispatchers.Default)` 或跟随生命周期,防止协程泄露。 - **线程调度(Dispatchers)**: - `Dispatchers.Main`:UI 线程(Android/Compose)。 - `Dispatchers.IO`:网络、磁盘文件等阻塞 I/O 操作。 - `Dispatchers.Default`:计算密集型、复杂数据处理。 - 线程切换使用 `withContext(Dispatchers.IO) { ... }` 即可。 - **并发任务**:多个耗时任务同时跑用 `async { ... }`,最后再调用 `.await()` 获取结果。 - **响应式数据流**:状态监听推荐用 `StateFlow` 或 `SharedFlow`,替代传统的回调接口。 ## 不依赖网络框架的网络 api 如果你不想引入 Spring Boot 或 Ktor 这样庞大的框架,只是想发个请求或者写个简单的接口: ### 发送 HTTP 请求(客户端) 直接用 Java 11+ 原生自带的 `HttpClient` 即可,零依赖且原生支持异步: ```kotlin import java.net.URI import java.net.http.HttpClient import java.net.http.HttpRequest import java.net.http.HttpResponse val client = HttpClient.newHttpClient() val request = HttpRequest.newBuilder() .uri(URI.create("https://api.github.com")) .GET() .build() val response = client.send(request, HttpResponse.BodyHandlers.ofString()) println(response.body()) ``` 如果是 KMP 跨平台客户端,首选官方轻量客户端 `io.ktor:ktor-client-core`。 ### 极简 HTTP 服务端 JDK 自带了轻量级的 `HttpServer`,适合写小工具或内网 Mock: ```kotlin import com.sun.net.httpserver.HttpServer import java.net.InetSocketAddress val server = HttpServer.create(InetSocketAddress(8080), 0) server.createContext("/ping") { exchange -> val response = "pong" exchange.sendResponseHeaders(200, response.length.toLong()) exchange.responseBody.use { it.write(response.toByteArray()) } } server.start() ``` ## 加载动态链接库(JNA) 如果需要调用 C/C++ 编译出的动态链接库(`.dll` / `.so` / `.dylib`),比起折腾麻烦的 JNI 头文件和胶水代码,**JNA (Java Native Access)** 是 JVM 和 Android 上最轻松的选择。 依赖: ```kotlin dependencies { implementation("net.java.dev.jna:jna:5.14.0") // 如果是 Android 端则使用: // implementation("net.java.dev.jna:jna:5.14.0@aar") } ``` 使用时只需要定义一个接口继承 `com.sun.jna.Library`: ```kotlin import com.sun.jna.Library import com.sun.jna.Native interface MyNativeLib : Library { fun add(a: Int, b: Int): Int companion object { // "mylib" 对应 libmylib.so / mylib.dll val INSTANCE: MyNativeLib = Native.load("mylib", MyNativeLib::class.java) } } // 直接调用 C 函数 val result = MyNativeLib.INSTANCE.add(1, 2) ``` 注意,库文件需要放在特定的文件夹,这里参考[官方文档](https://github.com/java-native-access/jna/blob/master/www/GettingStarted.md) ## 与 C 混编(cinterop) 在 Kotlin/Native(编译为原生二进制的目标平台,如 iOS、Linux、macOS、Windows)中,不需要 JVM 和 JNA,Kotlin 官方直接提供了 **cinterop** 工具。 1. 在项目源码旁新建 `.def` 文件(例如 `src/nativeInterop/cinterop/myclib.def`): ```properties headers = myclib.h staticLibraries = libmyclib.a libraryPaths = /path/to/lib ``` 2. 在 `build.gradle.kts` 中声明 cinterop: ```kotlin kotlin { linuxX64 { binaries.executable() compilations.getByName("main").cinterops { val myclib by creating } } } ``` 3. Gradle 构建后会自动生成 Kotlin 绑定包,在代码中直接 import 即可像调用普通 Kotlin 函数一样调用 C 函数,并通过 `memScoped` 安全管理 C 指针与内存。 ## 委托(Delegation 与 by 关键字) Kotlin 的 `by` 能极大精简代码,主要用在两个地方: ### 类委托 不必手动重写接口的所有方法再转发给内部对象,直接 `by` 代理: ```kotlin interface Repository { fun fetch(): String fun save(data: String) } // 缓存包装类,未重写的方法自动转发给 inner class CachedRepository(private val inner: Repository) : Repository by inner { override fun fetch(): String { return "from cache" // 只需重写你要拦截的方法 } } ``` ### 属性委托 除了常见的 `by lazy`,只要类提供了 `operator fun getValue / setValue`,就能代理属性的读写(Compose / KMP 里的 `var text by remember { mutableStateOf("") }` 就是如此): ```kotlin // 监听属性变化的标准库委托 var name: String by Delegates.observable("初始值") { prop, old, new -> println("$old -> $new") } ``` ## 内联值类 如果想给基础类型(如 `Long`、`Int`)包一层业务类型(例如 `UserId`、`OrderId`)以保证强类型安全,又不想每次创建对象都在堆内存里产生 GC 开销: ```kotlin @JvmInline value class UserId(val value: Long) fun getUser(id: UserId) { ... } ``` 编译后会在字节码里直接拆包还原成底层的原始类型,完全是零运行时开销。Compose 里的 `Color`、`Dp` 底层全部是用它实现的。 ## 优雅的异常处理:runCatching 在现代 Kotlin 代码中,尽量少写层层嵌套的 `try-catch`。标准库的 `runCatching` 更加函数式和连贯: ```kotlin val result = runCatching { // 可能会抛异常的代码 "123".toInt() }.getOrDefault(0) // 报错直接返回默认值,也可使用 getOrElse { ... } // 配合链式调用 runCatching { fetchNetworkData() } .onSuccess { data -> println("成功: $data") } .onFailure { error -> println("失败: ${error.message}") } ``` ## 大集合流式处理:Sequence 普通集合操作(`list.filter { }.map { }`)每一步都会立即创建一个全新的临时 `List`,在处理大数据或长链条时浪费大量内存。 加上 `asSequence()` 开启惰性求值(类似 Java 的 Stream),一个元素走完所有变换才处理下一个: ```kotlin val result = (1..100000).asSequence() .filter { it % 2 == 0 } .map { it * 2 } .take(10) // 只计算出前 10 个就提前停止,后面的根本不会去算 .toList() ``` ## Java 互操作注解 当 Kotlin 代码需要被 Java 代码调用,或者被依赖 Java 反射的旧框架识别时,别忘了这几个注解: - **`@JvmOverloads`**:给带有默认参数的函数自动生成 Java 重载方法,否则 Java 只能看到全参方法。 - **`@JvmStatic`**:把 `companion object` 或 `object` 里的函数真正编译成 Java 视角的 `static` 方法。 - **`@JvmField`**:直接暴露为底层公有字段,不生成 Kotlin 默认的 getter/setter。 ## 注解的使用处目标(Use-site Targets) Kotlin 声明一个属性 `val name: String`,在字节码里其实包含了:底层字段(field)、getter 方法、构造函数参数。 当配合 Spring、Room、JSON 序列化等注解使用时,如果不显式指定,注解可能会打在 getter 上导致框架失效。此时必须加上前缀: ```kotlin data class User( @field:NotBlank // 作用于字段 val username: String, @get:JsonIgnore // 作用于 getter 方法上 val secretToken: String ) ``` ## 将 jar 包上传至 Maven 仓库 这需要一个 gradle 插件: ```kotlin plugins { id("com.vanniktech.maven.publish") version "0.37.0" } ``` 具体的写法可以参考 [FFmpeg-Kit_KMP](https://github.com/SOR2171/FFmpeg-Kit_KMP/blob/main/settings.gradle.kts) 的 gradle 配置。