Menu
CoddyTech

init 代码块与验证

本课属于 Coddy Kotlin 学习旅程的“面向对象编程”单元。第 4 课,共 57 课。

创建实例时会运行 init 块,紧接着构造函数参数赋值之后。对于无法在单个属性声明中完成的初始化代码,可以放在这里:

class Order(val id: Int, items: List<Int>) {
    val total: Int
    val count: Int

    init {
        total = items.sum()
        count = items.size
        println("created order $id")
    }
}

在 main 中:

val o = Order(7, listOf(4, 6, 10))
println("${o.count} items, total ${o.total}")

输出:

created order 7
3 items, total 20

require(condition) { message }会检查参数,并在条件为 false 时抛出带有该消息的 IllegalArgumentException。将它放在 init 中,意味着永远无法创建无效实例:

class Percentage(val value: Int) {
    init {
        require(value in 0..100) { "percentage must be 0-100, was $value" }
    }
}

在 main 中:

println(Percentage(42).value)
try {
    Percentage(150)
} catch (e: IllegalArgumentException) {
    println(e.message)
}

输出:

42
percentage must be 0-100, was 150

一个类可以有多个 init 块;它们会按照从上到下的顺序与属性初始化器一起运行:

class Demo(name: String) {
    val first = "first: $name".also { println(it) }

    init { println("init 1") }

    val second = "second".also { println(it) }

    init { println("init 2") }
}

在 main 中:

Demo("x")
println("done")

输出:

first: x
init 1
second
init 2
done

在 init 中进行验证,可以让规则紧挨着数据。接收实例的代码可以信任它,无需再次检查:

class Email(val address: String) {
    init {
        require("@" in address) { "not an email: $address" }
    }
}
fun send(to: Email) { /* 不需要再次检查地址 */ }
challenge icon

挑战

简单

完成 Password 类。它的 init 代码块会使用 require 检查文本是否至少有 8 个字符(提示信息 too short),以及是否包含数字(提示信息 needs a digit),并按此顺序检查。strength 属性在 init 中计算:如果文本还包含大写字母,则值为 strong,否则为 ok。

提供的代码会为每行输入创建一个 Password,并输出 strength 或错误信息。

你的代码写在 Password.kt 中。Main.kt 保存了提供的输入输出代码,不能编辑。

亲手试试

fun main() {
    // 提供的输入输出代码:保持原样
    val input = generateSequence(::readLine).toList()
    for (line in input) {
        try {
            println(Password(line).strength)
        } catch (e: IllegalArgumentException) {
            println(e.message)
        }
    }
}
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: Kotlin 在线编辑器