【问题标题】:Kotlin - How to decide between "lateinit" and "nullable variable"?Kotlin - 如何在“lateinit”和“可空变量”之间做出决定?
【发布时间】:2017-06-28 07:25:42
【问题描述】:

我对 lateinit 和可为空的变量感到困惑,哪一个用于变量。

lateinit var c: String
var d: String? = null
c = "UserDefinedTarget"

// if not added initialisation for c than throws UninitializedPropertyAccessException
if (c == "UserDefinedTarget") {
    //do some stuff.
}
//not throws any exception whether d is initialise or not.
if(d == "UserDefinedTarget") {
     //do some stuff
}

【问题讨论】:

  • 如果您绝对确定变量会在使用前被初始化。您可以使用后期初始化。否则使用可为空的变量
  • for lateint add check if (this::c.isInitilized())

标签: android kotlin


【解决方案1】:

可以为 null 的类型就是这样,具有为 null 的有效状态的事物。

不可为空的后期初始化变量表示 null 是无效状态,但由于某种原因您不能在构造函数中填充它。

Android 活动是使用 lateinit 的一个很好的例子。活动必须有一个无参数的构造函数,并且它们的生命周期实际上只从 onCreate() 开始。

【讨论】:

  • lateinit 可以为空吗?
  • lateinit 仅用于避免将来进行空检查,这就是为什么 lateinit 修饰符不允许用于可空类型的属性。
【解决方案2】:

这是两个完全不同的概念。

您可以在引用属性时使用lateinit 来避免空检查。如果您的属性是通过依赖注入初始化的,或者例如在单元测试的 setup 方法中初始化,这将非常方便。

但是,您应该记住,在初始化之前访问 lateinit 属性会引发异常。这意味着只有在您绝对确定时才应该使用它们,它们被初始化。

另一方面,

可空类型在变量可以容纳 null 时使用。


class A {
    lateinit var a: String

    fun cat() {
        print(a.length)  // UninitializedPropertyAccessException is thrown
        a = "cat"
        print(a.length)  // >>> 3
    }
}

class B {
    var b: String? = null

    fun dog() {
        print(b.length)  // won't compile, null check is obligatory here
        print(b?.length) // >>> null
        b = "dog"
        print(b?.length) // >>> 3
    }
}

更多信息:

【讨论】:

    【解决方案3】:

    这取决于。 可空变量意味着变量可以保持值或空值。 lateinit 表示变量必须稍后初始化。它应该在访问它之前被初始化。如果您尝试访问未初始化的 lateinit 变量 UninitializedPropertyAccessException 将被抛出。

    最好避免在您的应用中使用空值。空值是邪恶的。因此,如果您可以在onCreate 中初始化变量,那么最好使用lateinit。此外,如果您在应用程序中使用依赖注入并且应该注入字段,那么使用lateinit 而不是处理空值也是一个有效的案例。

    如果由于某种原因您无法初始化变量,则初始化代码可能会导致 null,或者 null 可以分配给此变量,而不是您应该使用可为 null 的变量。一般来说,如果 null 是变量的有效值。

    【讨论】:

      【解决方案4】:

      lateinit 用于无法在构造函数中初始化的属性。

      【讨论】:

      • 你的意思是 usse lateinit 用于可以在构造函数中初始化的属性。如果您使用 lateinit 并且不将其初始化为构造函数,那么您将冒着在初始化之前访问它的风险,从而导致异常。
      • @ant2009 如果您要在构造函数中初始化它,那么根据定义,该属性不是lateinit。如果您在构造函数中初始化 lateinit 属性,Kotlin 编译器会发出 UNNECESSARY_LATEINIT 警告。
      • @TheKvist 感谢您指出这一点。如果在构造函数中初始化了 lateinit 属性,则始终保证初始化它,因为构造函数将始终运行。但是,如果你有一个 lateinit 属性并且它没有在构造函数中初始化,而是在另一个方法中,你总是可以使用 if(::fullName.isInitialized()) { /* do something */ } 来检查它是否已经初始化。这是我通常做的。
      • @ant2009 使用isInitialized 是你应该做的:) 刚刚意识到你的原始评论已经有一年多了,很抱歉死了,谢谢你的回复!问题是,如果您可以保证将在构造函数中初始化属性,则没有理由将该属性标记为lateinit,因为它永远不会“稍后初始化”,因此会发出编译器警告。就个人而言,在我有lateinit props 的类中,我定义了一个简单的validate 方法,该方法检查自己是否要初始化lateinit,如果没有则抛出异常。
      【解决方案5】:

      后期初始化变量

      • Lateinit 仅允许用于非原始数据类型,并且 变量不能为空类型。

      • 另外,lateinit 变量可以在类中声明,也可以在类中声明 可以是顶级属性。

      • 顾名思义,您必须在使用该变量之前对其进行初始化 否则它会抛出一个UninitializedPropertyAccessException,所以 请务必尽快初始化您的属性。

      • 不能和val一起使用,只能和var一起使用

      例如private var lateinit str:String

      可空变量

      • 这意味着你有能力声明一个变量是否可以 是否保持空值。
      • 通过在类型系统中支持可空性,编译器可以检测 编译时可能出现NullPointerException 错误并减少 有可能在运行时抛出它们。

      例如private var str:String?=null

      【讨论】:

        猜你喜欢
        • 2020-04-26
        • 2013-12-30
        • 2021-01-11
        • 1970-01-01
        • 2016-06-11
        • 2017-07-25
        • 2011-05-19
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多