Kotlin by lazy抛出NullPointerException

Kotlin by lazy抛出NullPointerException,kotlin,exception,nullpointerexception,null,Kotlin,Exception,Nullpointerexception,Null,我目前正试图通过《科特林编程大书呆子牧场指南》一书来学习科特林,到目前为止,一切都很顺利。 但现在我正在努力进行“惰性”初始化,它抛出一个NullPointerException 无法调用“kotlin.Lazy.getValue()”,因为“”为空 相应的行是: val hometown by lazy { selectHometown() } private fun selectHometown(): String = File("data/towns.txt").re

我目前正试图通过《科特林编程大书呆子牧场指南》一书来学习科特林,到目前为止,一切都很顺利。 但现在我正在努力进行“惰性”初始化,它抛出一个NullPointerException

无法调用“kotlin.Lazy.getValue()”,因为“”为空

相应的行是:

val hometown by lazy { selectHometown() } 
private fun selectHometown(): String = File("data/towns.txt").readText().split("\n").shuffled().first()
如果你想自己编译或者需要更多的代码来更好的理解,我会在下面提供Game.kt和Player.kt。如果为“正常”初始化删除了“lazy”,则会按预期分配家乡。 欢迎提供解决问题和了解问题原因的任何提示

// 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()}")
}
我忘记了towns.txt,所以它在这里(并不重要)


当发生这种情况时,通常是由于初始化顺序错误

Player
类的初始化如下:

  • name
    属性的支持字段已用
    \u name
    值初始化
  • 运行
    init
    块,并尝试访问
    name
  • name
    的getter尝试读取
    homightry
    属性,但失败,因为
    homightry
    仍未初始化
  • …如果一切正常,那么现在就可以使用惰性委托初始化
    homightry
    属性
  • 因此,基本上,在配置惰性委托之前,您要尝试访问
    家乡。
    如果您将
    家乡
    的声明移动到
    init
    块上方,您就可以了


    您可以看到正在运行的修复程序

    当发生类似情况时,通常是由于初始化顺序错误

    Player
    类的初始化如下:

  • name
    属性的支持字段已用
    \u name
    值初始化
  • 运行
    init
    块,并尝试访问
    name
  • name
    的getter尝试读取
    homightry
    属性,但失败,因为
    homightry
    仍未初始化
  • …如果一切正常,那么现在就可以使用惰性委托初始化
    homightry
    属性
  • 因此,基本上,在配置惰性委托之前,您要尝试访问
    家乡。
    如果您将
    家乡
    的声明移动到
    init
    块上方,您就可以了


    你可以看到修复的效果

    我一回家就试试你的建议。但是,无论代码放在类中的什么位置,init不会在构造之后立即执行吗?不会。属性初始值设定项和
    init
    块是按自上而下的顺序运行的。任何构造函数体在所有属性和
    init
    块之后运行(而构造函数参数在属性/init之前计算)。原因已确认。  (在您发布此邮件之前,我发现了问题:-)  @Tignite这将是一个很好的锻炼你(以及节省所有你的读者的麻烦)创造一个;这样做会告诉你问题在哪里,你需要什么来触发它。  (我得到了大约10行非空白代码。)@Tignite你可以在这里阅读更多关于类初始化顺序复杂性的信息:@gidds我在发布之前在play.kotlinlang.org上测试了修复程序:)我不能100%确定的原因是因为在操场上文件访问由于安全原因失败:D现在我用一个哑字符串替换了,我确认这是有效的,我一回家就会尝试你的建议。但是,无论代码放在类中的什么位置,init不会在构造之后立即执行吗?不会。属性初始值设定项和
    init
    块是按自上而下的顺序运行的。任何构造函数体在所有属性和
    init
    块之后运行(而构造函数参数在属性/init之前计算)。原因已确认。  (在您发布此邮件之前,我发现了问题:-)  @Tignite这将是一个很好的锻炼你(以及节省所有你的读者的麻烦)创造一个;这样做会告诉你问题在哪里,你需要什么来触发它。  (我得到了大约10行非空白代码。)@Tignite你可以在这里阅读更多关于类初始化顺序复杂性的信息:@gidds我在发布之前实际上在play.kotlinlang.org上测试了修复程序:)我不能100%确定的原因是因为在操场上由于安全原因文件访问失败:D现在我用一个哑字符串替换了,我确认它有效
    // 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!"
            }
    
    }
    
    Neversummer
    Abelhaven
    Phandoril
    Tampa
    Sanorith
    Trell
    Zan'tro
    Hermi Hermi
    Curlthistle Forest