在Kotlin中有两种不同的方式来延迟初始化属性:lateinit和lazy。
lateinit — 应用于稍后初始化的变量(var)的修饰符,通常通过依赖注入(DI)或在初始化块中进行初始化。仅适用于非静态的非空类型变量。在初始化之前访问会抛出UninitializedPropertyAccessException异常。
class MyClass { lateinit var data: String fun init() { data = "Hello!" } }
lazy — 应用于val 属性的特殊委托(仅限只读)。初始化表达式在第一次访问变量时计算。默认情况下对多线程访问是安全的。
val config: Config by lazy { loadConfigFromFile() }
lateinit不适用于原始类型和val。lazy不允许重新初始化。lateinit用于那些保证稍后会被赋值的变量(例如,通过DI框架或在Android生命周期中的片段)。lazy用于延迟计算,当值的计算成本高且可能不会被请求时。可以将
lateinit用于Int类型的属性吗?
答案: 不可以。lateinit仅适用于对象的非空类型。对于原始类型和可空类型 — 不可以。尝试声明lateinit var a: Int会导致编译错误。
故事
在一个教育项目中,声明了一个配置变量为lateinit var config: Config?,但是编译器不允许这样做 — 节省了时间,但必须弄清楚为什么不如预期工作。
故事
在Android应用程序中,忘记在调用之前检查lateinit属性是否初始化。这导致应用程序在生产环境中崩溃 — 设计师在onCreateView之前尝试访问属性。额外的检查提供了帮助。
故事
在使用多线程时,开发人员对耗资源的对象初始化应用了by lazy,而没有传递参数,误以为默认委托不是线程安全的。最终在发布版本中出现了竞争条件的问题。通过传递相应的参数解决了这个问题:by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { ... }.