Kotlin 习题集 · 高级篇

Kotlin 习题集 · 高级篇

涵盖 DSL、反射、协程深层、委托、设计模式、性能优化等高级内容。


第一章 DSL 构建

1.1 类型安全构建器

题目: 使用类型安全构建器模式构建 HTML DSL,实现以下调用方式:

kotlin 复制代码
html {
    head {
        title { +"My Page" }
    }
    body {
        h1 { +"Welcome" }
        p { +"Hello, Kotlin!" }
    }
}

答案:

kotlin 复制代码
// 定义可嵌套的元素接口
open class Tag(val name: String) {
    val children = mutableListOf<Tag>()
    
    protected fun <T : Tag> initTag(tag: T, init: T.() -> Unit): T {
        tag.init()
        children.add(tag)
        return tag
    }
    
    override fun toString() = "<$name>${children.joinToString("")}</$name>"
}

class HTML : Tag("html") {
    fun head(init: Head.() -> Unit) = initTag(Head(), init)
    fun body(init: Body.() -> Unit) = initTag(Body(), init)
}

class Head : Tag("head") {
    fun title(init: Title.() -> Unit) = initTag(Title(), init)
}

class Title : Tag("title") {
    operator fun String.unaryPlus() {
        children.add(TextNode(this))
    }
}

class Body : Tag("body") {
    fun h1(init: H1.() -> Unit) = initTag(H1(), init)
    fun p(init: P.() -> Unit) = initTag(P(), init)
}

class H1 : Tag("h1")
class P : Tag("p")

class TextNode(val text: String) : Tag("") {
    override fun toString() = text
}

// 顶层 DSL 入口
fun html(init: HTML.() -> Unit): HTML {
    val html = HTML()
    html.init()
    return html
}

fun main() {
    val doc = html {
        head {
            title { +"My Page" }
        }
        body {
            h1 { +"Welcome" }
            p { +"Hello, Kotlin!" }
        }
    }
    println(doc)
    // <html><head><title>My Page</title></head><body><h1>Welcome</h1><p>Hello, Kotlin!</p></body></html>
}

1.2 接收者类型与 it

题目: 实现一个 SQL 构建 DSL:

kotlin 复制代码
val query = select {
    from("users")
    where("age > 18")
    orderBy("name")
}

答案:

kotlin 复制代码
class QueryBuilder {
    private var table: String = ""
    private var whereClause: String? = null
    private var orderByClause: String? = null
    
    fun from(table: String) {
        this.table = table
    }
    
    fun where(condition: String) {
        this.whereClause = condition
    }
    
    fun orderBy(column: String) {
        this.orderByClause = column
    }
    
    fun build(): String {
        return buildString {
            append("SELECT * FROM $table")
            whereClause?.let { append(" WHERE $it") }
            orderByClause?.let { append(" ORDER BY $it") }
        }
    }
}

fun select(init: QueryBuilder.() -> Unit): QueryBuilder {
    val builder = QueryBuilder()
    builder.init()
    return builder
}

fun main() {
    val query = select {
        from("users")
        where("age > 18")
        orderBy("name")
    }
    println(query.build())
    // SELECT * FROM users WHERE age > 18 ORDER BY name
}

第二章 反射

2.1 基本反射操作

题目: 使用反射实现通用对象复制函数 deepCopy,能够复制任意对象的所有属性。

答案:

kotlin 复制代码
import kotlin.reflect.full.*
import kotlin.reflect.*

data class Person(val name: String, val age: Int)

class Address(val city: String, val zip: String)

data class Employee(
    val name: String,
    val age: Int,
    val address: Address
)

fun <T : Any> deepCopy(obj: T): T {
    val constructor = obj::class.primaryConstructor!!
    val params = constructor.parameters
    
    val args = params.map { param ->
        val value = obj::class.memberProperties
            .firstOrNull { it.name == param.name }
            ?.get(obj)
        
        when {
            param.type.isDataClass -> value?.let { deepCopy(it as Any) }
            param.type.isCollection -> (value as? List<*>)?.map { it?.let { deepCopy(it as Any) } }
            else -> value
        }
    }.toTypedArray()
    
    return constructor.call(*args)
}

fun main() {
    val addr = Address("Beijing", "100000")
    val emp1 = Employee("Alice", 30, addr)
    val emp2 = deepCopy(emp1)
    
    println(emp2)  // Employee(name=Alice, age=30, address=Address(city=Beijing, zip=100000))
    
    // 验证是深拷贝
    println(emp1.address === emp2.address)  // false (不同引用)
}

2.2 反射与注解

题目: 定义 @Config 注解,使用反射自动从配置文件读取值并注入到对象的属性。

答案:

kotlin 复制代码
import kotlin.reflect.*

@Target(AnnotationTarget.PROPERTY)
annotation class Config(val key: String)

class AppConfig {
    @Config("app.name")
    var appName: String = ""
    
    @Config("app.version")
    var version: String = ""
    
    @Config("app.debug")
    var debug: Boolean = false
}

fun loadConfig(config: AppConfig, configMap: Map<String, String>) {
    config::class.memberProperties.forEach { property ->
        val annotation = property.findAnnotation<Config>()
        if (annotation != null) {
            val value = configMap[annotation.key]
            if (value != null) {
                when (property.returnType) {
                    String::class.createType() -> property.setter.call(config, value)
                    Boolean::class.createType() -> property.setter.call(config, value.toBoolean())
                    Int::class.createType() -> property.setter.call(config, value.toInt())
                }
            }
        }
    }
}

fun main() {
    val map = mapOf(
        "app.name" to "MyApp",
        "app.version" to "1.0.0",
        "app.debug" to "true"
    )
    
    val config = AppConfig()
    loadConfig(config, map)
    
    println("App: ${config.appName}, Version: ${config.version}, Debug: ${config.debug}")
    // App: MyApp, Version: 1.0.0, Debug: true
}

第三章 协程深入

3.1 Channel 与 Fan-out/Fan-in

题目: 实现生产者-消费者模式,多个消费者从同一个 Channel 读取,实现 Fan-out(分发)和 Fan-in(合并)。

答案:

kotlin 复制代码
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*

fun CoroutineScope.producer(channel: SendChannel<Int>) {
    for (i in 1..5) {
        delay(100)
        channel.send(i * i)
    }
    channel.close()
}

fun main() = runBlocking {
    // Fan-out: 多个消费者从同一 Channel 读取
    val channel = produce<Int> {
        for (i in 1..5) {
            delay(100)
            send(i)
        }
        close()
    }
    
    // 启动两个消费者
    launch { for (v in channel) println("Consumer1: $v") }
    launch { for (v in channel) println("Consumer2: $v") }.join()
    
    // Fan-in: 多个生产者发送到同一 Channel
    val merged = GlobalScope.produce<Int> {
        val c1 = produce { for (i in 1..3) send(i) }
        val c2 = produce { for (i in 4..6) send(i) }
        merge(c1, c2).collect { send(it) }
    }
    
    println("Merged: ${merged.toList()}")
    
    // Buffer Channel
    val buffered = Channel<Int>(Channel.BUFFERED)
    launch {
        repeat(5) { buffered.send(it) }
    }
    launch {
        delay(50)
        buffered.receive()
        buffered.receive()
    }
}

3.2 Select 表达式

题目: 使用 select 同时等待多个协程结果,实现超时控制和时间最早的响应。

答案:

kotlin 复制代码
import kotlinx.coroutines.*
import kotlinx.coroutines.selects.*

suspend fun fetchFromAPI(name: String, delayMs: Long): String {
    delay(delayMs)
    return "$name result"
}

fun main() = runBlocking {
    // 等待最快的响应
    val result = select<String> {
        launch { fetchFromAPI("fast", 100).also { println("fast ready") } .onJoin { 
            onSelect { "fast" } 
        } }
        
        fetchFromAPI("slow", 500).onAwait { result ->
            onSelect { result }
        }
    }
    println("First: $result")  // fast
    
    // 超时控制
    val withTimeout = withTimeoutOrNull(200) {
        select {
            fetchFromAPI("api1", 100).onAwait { it }
            fetchFromAPI("api2", 300).onAwait { it }
        }
    }
    println("Timeout result: $withTimeout")  // null (都超时)
    
    // Channel select
    val ch1 = Channel<Int>()
    val ch2 = Channel<Int>()
    
    launch { ch1.send(1) }
    launch { ch2.send(2) }
    
    val received = select<Int> {
        ch1.onReceive { it }
        ch2.onReceive { it }
    }
    println("Received: $received")
}

3.3 Flow 高级操作

题目: 实现自定义 Flow 操作符 distinctUntilChanged,仅在值变化时发射;实现 scan 操作。

答案:

kotlin 复制代码
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*

// distinctUntilChanged: 只发射与前一个不同的值
fun <T> Flow<T>.distinctUntilChanged(): Flow<T> = flow {
    var previous: T? = null
    collect { value ->
        if (value != previous) {
            previous = value
            emit(value)
        }
    }
}

// 自定义中间操作符
fun <T, R> Flow<T>.mapNotNull(transform: suspend (T) -> R?): Flow<R> = flow {
    collect { value ->
        transform(value)?.let { emit(it) }
    }
}

// 自定义终端操作符
suspend fun <T> Flow<T>.firstOrFail(message: String): T {
    var result: T? = null
    collect { result = it }
    return result ?: throw IllegalStateException(message)
}

fun main() = runBlocking {
    // 测试 distinctUntilChanged
    flowOf(1, 1, 2, 2, 2, 3, 1)
        .distinctUntilChanged()
        .collect { print("$it ") }  // 1 2 3 1
    
    println()
    
    // scan: 累积操作
    flowOf(1, 2, 3, 4)
        .scan(0) { acc, value -> acc + value }
        .collect { print("$it ") }  // 0 1 3 6 10
    
    println()
    
    // combineLatest
    val nameFlow = flowOf("Alice", "Bob", "Carol")
    val ageFlow = flowOf(25, 30)
    
    combine(nameFlow, ageFlow) { name, age ->
        "$name is $age"
    }.collect { println(it) }
}

3.4 共享状态与并发安全

题目: 实现线程安全的计数器,使用 MutexAtomicIntChannel 三种方式。

答案:

kotlin 复制代码
import kotlinx.coroutines.*
import kotlinx.coroutines.sync.*
import java.util.concurrent.atomic.*

// 方式1: Mutex
suspend fun counterWithMutex(init: Int = 0): Int {
    var count = init
    val mutex = Mutex()
    
    coroutineScope {
        repeat(1000) {
            launch {
                mutex.withLock {
                    count++
                }
            }
        }
    }
    return count
}

// 方式2: AtomicInt
suspend fun counterWithAtomic(): Int {
    val count = AtomicInteger(0)
    
    coroutineScope {
        repeat(1000) {
            launch {
                count.incrementAndGet()
            }
        }
    }
    return count.get()
}

// 方式3: Channel 作为信号量
suspend fun counterWithChannel(): Int {
    var count = 0
    val channel = Channel<Unit>(Channel.CONFLATED)
    
    coroutineScope {
        repeat(1000) {
            launch { channel.send(Unit) }
        }
        repeat(1000) {
            channel.receive()
            count++
        }
    }
    return count
}

fun main() = runBlocking {
    println("Mutex: ${counterWithMutex()}")
    println("Atomic: ${counterWithAtomic()}")
    println("Channel: ${counterWithChannel()}")
    
    // Actor 模式
    val counterActor = GlobalScope.actor<Int> {
        var count = 0
        channel.consumeEach {
            count += it
            if (count >= 10) {
                println("Count reached $count")
            }
        }
    }
    
    repeat(10) { counterActor.offer(1) }
}

第四章 委托机制

4.1 委托属性基础

题目: 实现一个懒加载属性委托 lazy,模拟其实现方式。

答案:

kotlin 复制代码
import kotlin.reflect.*

// 自定义懒加载委托
class Lazy<T>(initializer: () -> T) {
    private var initializer: (() -> T)? = initializer
    private var _value: Any? = null
    private var initialized = false
    
    operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
        if (!initialized) {
            _value = initializer!!()
            initialized = true
            initializer = null
        }
        @Suppress("UNCHECKED_CAST")
        return _value as T
    }
}

class Person {
    val name: String by Lazy { 
        println("Computing name...")  // 只打印一次
        "Alice" 
    }
}

fun main() {
    val p = Person()
    println("Created")
    println(p.name)  // Computing name... / Alice
    println(p.name)  // 直接返回 Alice(不再计算)
    
    // 标准库 lazy
    val lazyValue: String by lazy {
        println("Lazy init")
        "Computed"
    }
    println(lazyValue)  // Lazy init / Computed
    println(lazyValue)  // Computed
}

4.2 Observable 与 Vetoable

题目: 实现 observable 委托,在值变化时打印旧值和新值;实现 vetoable,仅当新值满足条件时才更新。

答案:

kotlin 复制代码
import kotlin.properties.*
import kotlin.reflect.*

// observable: 每次赋值后调用回调
class ObservableVar<T>(initial: T, val onChange: (T) -> Unit) {
    private var value = initial
    
    operator fun getValue(thisRef: Any?, property: KProperty<*>) = value
    
    operator fun setValue(thisRef: Any?, property: KProperty<*>, newValue: T) {
        println("${property.name}: $value -> $newValue")
        value = newValue
        onChange(newValue)
    }
}

// vetoable: 回调返回 true 才接受新值
class VetoableVar<T>(initial: T, val predicate: (T) -> Boolean) {
    private var value = initial
    
    operator fun getValue(thisRef: Any?, property: KProperty<*>) = value
    
    operator fun setValue(thisRef: Any?, property: KProperty<*>, newValue: T): Boolean {
        return if (predicate(newValue)) {
            println("${property.name}: $value -> $newValue (accepted)")
            value = newValue
            true
        } else {
            println("${property.name}: $newValue rejected (predicate failed)")
            false
        }
    }
}

class User {
    var name: String by ObservableVar("Unknown") { newValue ->
        println("User name changed to: $newValue")
    }
    
    var age: Int by ObservableVar(0) { println("Age updated: $it") }
}

fun main() {
    val user = User()
    user.name = "Alice"  // name: Unknown -> Alice
    user.name = "Bob"    // name: Alice -> Bob
    user.age = 25        // Age updated: 25
    
    // vetoable
    var score: Int by VetoableVar(0) { it in 0..100 }
    score = 50   // score: 0 -> 50 (accepted)
    score = 150  // score: 150 rejected (predicate failed)
    println(score)  // 50
}

4.3 委托类实现

题目: 实现 ReadOnlyMap 委托,允许通过属性访问 Map 的值。

答案:

kotlin 复制代码
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.*

class MapDelegate<K, V>(private val map: Map<K, V>) : ReadOnlyProperty<Any?, V> {
    override operator fun getValue(thisRef: Any?, property: KProperty<*>): V {
        val key = property.name
        return map[key as? K] ?: throw IllegalStateException("Key $key not found")
    }
}

// 便捷函数
fun <K, V> mapDelegate(map: Map<K, V>) = MapDelegate(map)

class Config {
    private val settings = mapOf(
        "host" to "localhost",
        "port" to 8080,
        "debug" to true
    )
    
    val host: String by MapDelegate(settings)
    val port: Int by MapDelegate(settings)
    val debug: Boolean by MapDelegate(settings)
}

fun main() {
    val config = Config()
    println(config.host)   // localhost
    println(config.port)    // 8080
    println(config.debug)   // true
    
    // 使用扩展函数
    val user = UserData(mapOf("name" to "Alice", "age" to "30"))
    println(user.name)  // Alice
    println(user.age)   // 30
}

class UserData(private val props: Map<String, String>) {
    val name: String by mapDelegate(props)
    val age: String by mapDelegate(props)
}

4.4 委托与懒加载工厂

题目: 实现类委托,使用 by 关键字将接口实现委托给另一个对象。

答案:

kotlin 复制代码
interface Base {
    fun print()
}

class BaseImpl(val x: Int) : Base {
    override fun print() = println("BaseImpl: $x")
}

// 类委托:Delegate 将接口实现委托给 impl
class Derived(b: Base) : Base by b

interface Collection<T> {
    fun isEmpty(): Boolean
}

class ListCollection<T>(private val list: List<T>) : Collection<T> by list

fun main() {
    val base = BaseImpl(42)
    val derived = Derived(base)
    derived.print()  // BaseImpl: 42
    
    val coll: Collection<Int> = ListCollection(listOf(1, 2, 3))
    println(coll.isEmpty())  // false
}

第五章 设计模式

5.1 单例模式

题目: 使用 Kotlin 实现线程安全的单例,包括饿汉式、懒汉式(双重检查)、Bill Pugh Singleton。

答案:

kotlin 复制代码
// 方式1: object 单例(Kotlin 原生支持)
object Singleton1 {
    fun greet() = "I am Singleton1"
}

// 方式2: 懒汉式(双重检查锁)
class Singleton2 private constructor() {
    companion object {
        @Volatile private var instance: Singleton2? = null
        
        fun getInstance(): Singleton2 {
            return instance ?: synchronized(this) {
                instance ?: Singleton2().also { instance = it }
            }
        }
    }
}

// 方式3: 懒汉式(线程局部)
class Singleton3 private constructor() {
    companion object {
        val instance: Singleton3 by lazy { Singleton3() }
    }
}

// 方式4: 枚举单例(防止反射攻击)
enum class Singleton4 {
    INSTANCE;
    fun greet() = "I am enum singleton"
}

fun main() {
    println(Singleton1.greet())  // I am Singleton1
    
    val s2a = Singleton2.getInstance()
    val s2b = Singleton2.getInstance()
    println(s2a === s2b)  // true
    
    val s3a = Singleton3.instance
    val s3b = Singleton3.instance
    println(s3a === s3b)  // true
    
    println(Singleton4.INSTANCE.greet())  // I am enum singleton
}

5.2 工厂模式与 Builder

题目: 使用 Kotlin 实现工厂模式,并结合 DSL 实现 Person 的 Builder。

答案:

kotlin 复制代码
// 工厂方法
sealed class Result {
    data class Success<T>(val data: T) : Result()
    data class Error(val message: String) : Result()
}

class ResultFactory {
    fun <T> success(data: T): Result.Success<T> = Result.Success(data)
    fun error(message: String): Result.Error = Result.Error(message)
}

// Person Builder
class Person private constructor(
    val name: String,
    val age: Int,
    val email: String?,
    val address: String?
) {
    class Builder {
        private var name: String = ""
        private var age: Int = 0
        private var email: String? = null
        private var address: String? = null
        
        fun name(name: String) = apply { this.name = name }
        fun age(age: Int) = apply { this.age = age }
        fun email(email: String?) = apply { this.email = email }
        fun address(address: String?) = apply { this.address = address }
        
        fun build(): Person {
            require(name.isNotBlank()) { "Name required" }
            return Person(name, age, email, address)
        }
    }
}

// DSL 风格 Builder
class PersonDsl {
    var name: String = ""
    var age: Int = 0
    var email: String? = null
    var address: String? = null
    
    fun build() = Person(name, age, email, address)
}

fun person(init: PersonDsl.() -> Unit) = PersonDsl().apply(init).build()

fun main() {
    // 工厂模式
    val factory = ResultFactory()
    val success: Result<Int> = factory.success(42)
    val error: Result<String> = factory.error("Not found")
    
    // Builder 模式
    val person1 = Person.Builder()
        .name("Alice")
        .age(30)
        .email("alice@example.com")
        .build()
    
    println("${person1.name}, ${person1.age}, ${person1.email}")
    
    // DSL Builder
    val person2 = person {
        name = "Bob"
        age = 25
        email = "bob@example.com"
    }
    
    println("${person2.name}, ${person2.age}")
}

5.3 策略模式与模板方法

题目: 使用 Lambda 和高阶函数实现策略模式,用扩展函数实现模板方法。

答案:

kotlin 复制代码
// 策略模式:使用 Lambda
class PaymentProcessor {
    fun pay(amount: Double, strategy: (Double) -> Boolean) {
        if (strategy(amount)) {
            println("Payment of $$amount succeeded")
        } else {
            println("Payment failed")
        }
    }
}

val creditCardStrategy: (Double) -> Boolean = { amount ->
    println("Processing credit card...")
    amount <= 1000
}

val paypalStrategy: (Double) -> Boolean = { amount ->
    println("Processing PayPal...")
    amount <= 5000
}

fun main() {
    val processor = PaymentProcessor()
    
    processor.pay(500.0, creditCardStrategy)  // Processing credit card... / succeeded
    processor.pay(6000.0, paypalStrategy)     // Processing PayPal... / failed
    
    // 模板方法:定义骨架,具体实现延迟到子类
    abstract class DataProcessor {
        fun process() {
            val data = readData()
            val cleaned = cleanData(data)
            val result = analyze(cleaned)
            saveResult(result)
        }
        
        abstract fun readData(): String
        abstract fun cleanData(data: String): String
        abstract fun analyze(data: String): String
        open fun saveResult(result: String) {
            println("Saving: $result")
        }
    }
    
    class TextProcessor : DataProcessor() {
        override fun readData() = "raw text data"
        override fun cleanData(data: String) = data.trim()
        override fun analyze(data: String) = data.uppercase()
    }
    
    TextProcessor().process()
}

第六章 内联类与值类

6.1 内联类基础

题目: 定义内联类 UserIdOrderId,实现类型安全的长度度量。

答案:

kotlin 复制代码
// 内联类:运行时零开销,编译时提供类型安全
inline class UserId(val value: String)
inline class OrderId(val value: String)

inline class Meters(val value: Double) {
    operator fun plus(other: Meters) = Meters(value + other.value)
    override fun toString() = "${value}m"
}

inline class PositiveInt(val value: Int) {
    init {
        require(value > 0) { "Must be positive" }
    }
}

fun main() {
    val userId = UserId("user-123")
    val orderId = OrderId("order-456")
    
    println(userId.value)  // user-123
    println(userId == orderId)  // false (类型不同,虽值相同)
    
    val length = Meters(5.0)
    val width = Meters(3.0)
    println(length + width)  // 8.0m
    
    val pos = PositiveInt(10)
    println(pos.value)  // 10
    
    // PositiveInt(-1)  // IllegalArgumentException: Must be positive
}

6.2 内联类与类型别名

题目: 说明内联类和类型别名的区别,以及各自的适用场景。

答案:

kotlin 复制代码
// 类型别名:运行时还是同一类型,无类型安全
typealias UserName = String
typealias Email = String

fun sendEmail(email: Email, message: String) {
    println("Sending to $email: $message")
}

// 内联类:编译时是不同类型,有类型安全
inline class Password(val value: String)
inline class Token(val value: String)

fun authenticate(token: Token) {
    println("Authenticating with token: ${token.value}")
}

fun main() {
    val name: UserName = "Alice"
    val email: Email = "alice@example.com"
    
    // 类型别名:String 和 String 可互换
    sendEmail(name, "Hello")  // 可以,String 可赋值给 Email
    
    // 内联类:类型安全,不会混淆
    val token = Token("abc123")
    authenticate(token)
    
    // Token("abc") != Password("abc") (编译期错误)
    
    // 适用场景:
    // - 类型别名:内部使用,不暴露给外部 API
    // - 内联类:公开 API,需要类型安全防止误用
}

第七章 性能与优化

7.1 集合操作性能

题目: 比较不同集合操作的时间复杂度,选择合适的数据结构实现高效查找。

答案:

kotlin 复制代码
fun main() {
    // 列表查找:O(n)
    val list = List(100000) { it }
    println(list.contains(99999))  // true
    
    // Set 查找:O(1)
    val set = list.toSet()
    println(set.contains(99999))  // true
    
    // Map 查找:O(1)
    val map = list.associateWith { "value_$it" }
    println(map[99999])  // value_99999
    
    // 避免:list.filter { condition }.firstOrNull() 效率低
    // 正确:list.firstOrNull { condition }
    
    // 批量操作
    val numbers = (1..100000).toList()
    
    // 差: 多次遍历
    val result1 = numbers.map { it * 2 }.filter { it > 100 }.take(10)
    
    // 好: 一次遍历
    val result2 = numbers.asSequence()
        .map { it * 2 }
        .filter { it > 100 }
        .take(10)
        .toList()
    
    // Sequence(懒加载)在大数据集时更优
    println(result2)  // [102, 104, 106, ...]
    
    // 使用 groupBy 而非手动分组
    val grouped = numbers.groupBy { it % 10 }
    println(grouped[0]?.last())  // 99990
}

7.2 内联函数与对象分配

题目: 说明 inline 函数何时能提升性能,何时会适得其反。

答案:

kotlin 复制代码
// 适合内联的场景:Lambda 参数,创建新作用域
inline fun <T> measureTime(block: () -> T): T {
    val start = System.currentTimeMillis()
    val result = block()
    println("Elapsed: ${System.currentTimeMillis() - start}ms")
    return result
}

// 不适合内联的场景:Lambda 传递给其他函数(非局部返回)
inline fun foo(inlined: () -> Unit, crossinline notInlined: () -> Unit) {
    inlined()
    notInlined()
}

// reified 内联函数
inline fun <reified T> getTypeName() = T::class.simpleName

fun main() {
    // 适合内联
    val result = measureTime {
        Thread.sleep(10)
        "done"
    }
    
    // reified 获取类型
    println(getTypeName<String>())  // String
    println(getTypeName<Int>())     // Int
    
    // 内联的反面:代码膨胀
    // inline 不适合的场景:
    // - 函数体大
    // - 调用次数少(减少代码复用性)
    // - 递归函数
    // - 参数中有非内联 Lambda
}

第八章 协程与 Flow 实战

8.1 协程取消与超时

题目: 实现一个可取消的任务,使用 withTimeoutwithTimeoutOrNull,并处理 CancellationException

答案:

kotlin 复制代码
import kotlinx.coroutines.*

fun main() = runBlocking {
    // withTimeout: 超时抛出异常
    try {
        withTimeout(100) {
            repeat(1000) { i ->
                println("Task $i")
                delay(10)
            }
        }
    } catch (e: TimeoutCancellationException) {
        println("Timed out!")
    }
    
    // withTimeoutOrNull: 超时返回 null
    val result = withTimeoutOrNull(100) {
        repeat(1000) { i ->
            println("Task $i")
            delay(10)
        }
        "Completed"
    }
    println("Result: $result")  // null
    
    // 协程取消:检查 isActive
    val job = launch {
        try {
            repeat(1000) { i ->
                if (!isActive) {
                    println("Cancelled at $i")
                    break
                }
                println("Working $i")
                delay(5)
            }
        } finally {
            // 清理代码一定会执行
            println("Cleanup!")
        }
    }
    
    delay(50)
    println("Cancelling...")
    job.cancelAndJoin()
    println("Cancelled")
}

8.2 Flow 异常处理

题目: 实现 Flow 的错误处理,使用 catchretryonEach 转换错误。

答案:

kotlin 复制代码
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*

fun main() = runBlocking {
    // catch: 捕获上游异常
    flow {
        emit(1)
        emit(2)
        throw RuntimeException("Error!")
    }.catch { e ->
        println("Caught: ${e.message}")
        emit(-1)  // 发出替代值
    }.collect { println(it) }  // 1, 2, -1
    
    // retry: 自动重试
    var attempts = 0
    flow {
        attempts++
        if (attempts < 3) throw RuntimeException("Retry $attempts")
        emit("Success!")
    }.retry(3) { e ->
        println("Retrying: ${e.message}")
        true  // 重试条件
    }.catch { e ->
        println("All retries failed: ${e.message}")
    }.collect { println(it) }
    
    // onEach / onCompletion
    flowOf(1, 2, 3, 4, 5)
        .onEach { if (it == 3) throw RuntimeException("Bad number") }
        .onEach { println("Processing $it") }
        .catch { println("Error: ${it.message}") }
        .onCompletion { println("Flow completed") }
        .collect { }
    
    // 决赛选手模式:combineTransform
    val f1 = flowOf(1, 2, 3)
    val f2 = flowOf("a", "b")
    
    combine(f1, f2) { num, str -> "$str$num" }
        .onEach { println(it) }
        .launchIn(this)
    
    delay(100)
}

答案汇总索引

章节 题目 核心知识点
1.1-1.2 DSL 类型安全构建器、接收者类型、Lambda DSL
2.1-2.2 反射 KProperty、data class 反射、注解处理
3.1-3.4 协程深入 Channel、Select、Flow 高级、并发安全
4.1-4.4 委托 委托属性、observable、vetoable、类委托
5.1-5.3 设计模式 单例、工厂、Builder、策略、模板方法
6.1-6.2 内联类 值类、类型安全、类型别名对比
7.1-7.2 性能 集合复杂度、Sequence、内联优化
8.1-8.2 协程实战 取消超时、Flow 异常处理、重试

恭喜完成 Kotlin 全套习题!持续练习,编码能力更进一步 🚀

相关推荐
楼兰公子2 小时前
buildroot 在编译rust时裁剪平台类型数量的方法
开发语言·后端·rust
吴声子夜歌2 小时前
Go——并发编程
开发语言·后端·golang
ooseabiscuit3 小时前
Laravel4.x:现代PHP框架的奠基之作
java·开发语言·php
问心无愧05133 小时前
ctf show web 入门42
android·前端·android studio
c1s2d3n4cs3 小时前
Qt模仿nlohmann::json进行序列化和反序列化
开发语言·qt·json
没什么本事4 小时前
关于C# panel 添加lable问题 -- 明确X和Y 位置错误
android·java·c#
AiTop1004 小时前
Claude Code 推出 Agent View:命令行编程正式进入“多线程并发“时代
开发语言·人工智能·ai·aigc
jf加菲猫4 小时前
第21章 Qt WebEngine
开发语言·c++·qt·ui
码农-阿杰5 小时前
深入理解 synchronized 底层实现:从 HotSpot C++ 源码看对象锁与 Monitor 机制
开发语言·c++·