Kotlin 通过懒惰抛出 NullPointerException
Kotlin by lazy throws NullPointerException
我目前正在尝试借助“Kotlin Programming The Big Nerd Ranch Guide”一书学习 Kotlin,到目前为止一切正常。
但是现在我正在努力处理抛出 NullPointerException 的“惰性”初始化,它说
Cannot invoke "kotlin.Lazy.getValue()" because "< local1>" is null
对应的行是:
val hometown by lazy { selectHometown() }
private fun selectHometown(): String = File("data/towns.txt").readText().split("\n").shuffled().first()
如果您想自己编译它或需要更多代码以便更好地理解,我在下面提供了 Game.kt 和 Player.kt。如果为“正常”初始化删除“惰性”,则会按预期分配家乡。
欢迎任何解决问题和了解问题原因的提示。
// Game.kt
package com.bignerdranch.nyethack
fun main(args: Array<String>) {
val player = Player("Madrigal")
player.castFireball()
}
private fun printPlayerStatus(player: Player) {
println("(Aura: ${player.auraColor()}) " + "(Blessed: ${if (player.isBlessed) "YES" else "NO"})")
println("${player.name} ${player.formatHealthStatus()}")
}
// Player.kt
package com.bignerdranch.nyethack
import java.io.File
class Player(_name: String, var healthPoints: Int = 100, val isBlessed: Boolean, private val isImmortal: Boolean) {
var name = _name
get() = "${field.capitalize()} of $hometown"
private set(value) {
field = value.trim()
}
constructor(name: String) : this(name, isBlessed = true, isImmortal = false) {
if (name.toLowerCase() == "kar") healthPoints = 40
}
init {
require(healthPoints > 0, { "healthPoints must be greater than zero." })
require(name.isNotBlank(), { "Player must have a name" })
}
val hometown by lazy { selectHometown() }
private fun selectHometown(): String = File("data/towns.txt").readText().split("\n").shuffled().first()
fun castFireball(numFireballs: Int = 2) =
println("A glass of Fireball springs into existence. (x$numFireballs)")
fun auraColor(): String {
val auraVisible = isBlessed && healthPoints > 60 || isImmortal
return if (auraVisible) "GREEN" else "NONE"
}
fun formatHealthStatus() =
when (healthPoints) {
100 -> "is an excellent condition!"
in 90..99 -> "has a few scratches."
in 75..89 -> if (isBlessed) {
"has some minor wounds but is healing quite quickly"
} else {
"has some minor wounds"
}
in 15..74 -> "looks pretty hurt"
else -> "is in awful condition!"
}
}
我忘记了 towns.txt 所以在这里(不是很重要)
Neversummer
Abelhaven
Phandoril
Tampa
Sanorith
Trell
Zan'tro
Hermi Hermi
Curlthistle Forest
发生这种情况时,通常是因为初始化顺序错误。
Player
class 的初始化是这样的:
name
属性 的支持字段已使用 _name
值初始化
init
块是 运行,并尝试访问 name
-
name
的 getter 尝试读取 hometown
属性,但失败了,因为 hometown
仍未初始化
- ...如果一切顺利,
hometown
属性 现在将使用惰性委托 进行初始化
所以基本上您是在配置惰性委托之前尝试访问 hometown
。
如果将 hometown
的声明移到 init
块上方,应该没问题。
您可以看到正在运行的修复程序 on the playground
我目前正在尝试借助“Kotlin Programming The Big Nerd Ranch Guide”一书学习 Kotlin,到目前为止一切正常。 但是现在我正在努力处理抛出 NullPointerException 的“惰性”初始化,它说
Cannot invoke "kotlin.Lazy.getValue()" because "< local1>" is null
对应的行是:
val hometown by lazy { selectHometown() }
private fun selectHometown(): String = File("data/towns.txt").readText().split("\n").shuffled().first()
如果您想自己编译它或需要更多代码以便更好地理解,我在下面提供了 Game.kt 和 Player.kt。如果为“正常”初始化删除“惰性”,则会按预期分配家乡。 欢迎任何解决问题和了解问题原因的提示。
// Game.kt
package com.bignerdranch.nyethack
fun main(args: Array<String>) {
val player = Player("Madrigal")
player.castFireball()
}
private fun printPlayerStatus(player: Player) {
println("(Aura: ${player.auraColor()}) " + "(Blessed: ${if (player.isBlessed) "YES" else "NO"})")
println("${player.name} ${player.formatHealthStatus()}")
}
// Player.kt
package com.bignerdranch.nyethack
import java.io.File
class Player(_name: String, var healthPoints: Int = 100, val isBlessed: Boolean, private val isImmortal: Boolean) {
var name = _name
get() = "${field.capitalize()} of $hometown"
private set(value) {
field = value.trim()
}
constructor(name: String) : this(name, isBlessed = true, isImmortal = false) {
if (name.toLowerCase() == "kar") healthPoints = 40
}
init {
require(healthPoints > 0, { "healthPoints must be greater than zero." })
require(name.isNotBlank(), { "Player must have a name" })
}
val hometown by lazy { selectHometown() }
private fun selectHometown(): String = File("data/towns.txt").readText().split("\n").shuffled().first()
fun castFireball(numFireballs: Int = 2) =
println("A glass of Fireball springs into existence. (x$numFireballs)")
fun auraColor(): String {
val auraVisible = isBlessed && healthPoints > 60 || isImmortal
return if (auraVisible) "GREEN" else "NONE"
}
fun formatHealthStatus() =
when (healthPoints) {
100 -> "is an excellent condition!"
in 90..99 -> "has a few scratches."
in 75..89 -> if (isBlessed) {
"has some minor wounds but is healing quite quickly"
} else {
"has some minor wounds"
}
in 15..74 -> "looks pretty hurt"
else -> "is in awful condition!"
}
}
我忘记了 towns.txt 所以在这里(不是很重要)
Neversummer
Abelhaven
Phandoril
Tampa
Sanorith
Trell
Zan'tro
Hermi Hermi
Curlthistle Forest
发生这种情况时,通常是因为初始化顺序错误。
Player
class 的初始化是这样的:
name
属性 的支持字段已使用_name
值初始化init
块是 运行,并尝试访问name
-
name
的 getter 尝试读取hometown
属性,但失败了,因为hometown
仍未初始化 - ...如果一切顺利,
hometown
属性 现在将使用惰性委托 进行初始化
所以基本上您是在配置惰性委托之前尝试访问 hometown
。
如果将 hometown
的声明移到 init
块上方,应该没问题。
您可以看到正在运行的修复程序 on the playground