可调试性
本章介绍关于可调试性需要注意的问题.
永远要提供 toString() 方法
为了便于调试, 要为你引入的每个类添加 toString()
方法的实现, 即使是对内部类也是如此. 如果 toString()
是契约(Contract) 的一部分, 那么要提供明确的文档说明.
下面的代码是图形建模代码简化后的例子:
class Vector2D(val x: Int, val y: Int)
fun main() {
val result = (1..20).map { Vector2D(it, it) }
println(result)
}
这段代码的输出没什么用处:
[Vector2D@27bc2616, Vector2D@3941a79c, Vector2D@506e1b77,...]
Debug Tool 窗口中提供的信息也没什么用处:
为了让日志和调试信息更加易于阅读, 请添加一个简单的 toString()
实现, 如下:
override fun toString(): String =
"Vector2D(x=$x, y=$y)"
改善后的输出如下:
[Vector2D(x=1, y=1), Vector2D(x=2, y=2), Vector2D(x=3, y=3), ...
即使你认为这个类不会在任何地方打印输出, 也应该考虑实现 toString()
, 因为它可能会以意想不到的方式提供帮助. 例如, 在 构建器 之内, 能够看到构建器目前的状态可能会非常重要.
class Person(
val name: String?,
val age: Int?,
val children: List<Person>
) {
override fun toString(): String =
"Person(name=$name, age=$age, children=$children)"
}
class PersonBuilder {
var name: String? = null
var age: Int? = null
val children = arrayListOf<Person>()
fun child(personBuilder: PersonBuilder.() -> Unit = {}) {
children.add(person(personBuilder))
}
}
fun person(personBuilder: PersonBuilder.() -> Unit = {}): Person {
val builder = PersonBuilder()
builder.personBuilder()
return Person(builder.name, builder.age, builder.children)
}
上面的代码预期的使用方式是:
如果你在第一个 child
的右大括号之后的行设置断点 (如上图所示), 你会在 Debug Output 中看到一个无意义的字符串:
如果你添加一个简单的 toString()
实现, 如下:
override fun toString(): String =
"PersonBuilder(name=$name, age=$age, children=$children)"
调试信息会变得更加清晰:
你还能立即看到哪些域变量已被设置, 哪些还没有设置.
下一步做什么?
学习 API 的 向后兼容性(Backward Compatibility).
最终更新: 2024/10/17