在 Scala 中,lazy 是一个关键字,用于延迟初始化变量,其核心作用是:变量的初始化不会在声明时执行,而是在第一次被使用时才执行。
具体作用与特性:
- 延迟初始化被
lazy修饰的变量(lazy val),在定义时不会立即分配内存或执行初始化逻辑,只有当它第一次被访问(读取或使用)时,才会执行初始化代码。 - 保证初始化一次即使被多次访问,
lazy val也只会初始化一次,后续访问直接使用已初始化的值(类似单例效果)。 - 解决初始化顺序问题在类或特质继承关系中,父类 / 特质的初始化可能早于子类,导致依赖的变量尚未赋值(如你之前遇到的
filename为null的问题)。lazy可以通过延迟初始化,确保依赖的变量在使用时已被正确初始化。 - 优化资源加载对于创建成本高的对象(如文件流、网络连接、大型数据结构),
lazy可以避免不必要的初始化(如果变量始终未被使用,则不会消耗资源)。
注意事项:
lazy只能修饰val(不可变变量),不能修饰var(可变变量),因为var可能被多次赋值,与 “初始化一次” 的特性冲突。- 过度使用
lazy可能隐藏初始化顺序问题,或因延迟执行导致调试困难,需合理使用。
简单说,lazy 的核心价值是:按需初始化,且只初始化一次,尤其适合解决依赖顺序问题和优化资源加载。
Lazy:
懒加载效果
||
这个对象不会立刻去创建,而是等到你需要使用的时候才去创建
错误代码 ↓ :
package level02
import java.io.FileWriter
/*
*/
object class13 {
trait FileLogger{
val filename:String
val writer = new FileWriter(filename)
def writeLog(msg:String): Unit = {
writer.write(msg)
writer.close()
}
}
class MyWriter extends FileLogger {
override val filename: String = "test.log"
}
def main(args: Array[String]): Unit = {
val log = new MyWriter()
log.writeLog("测试内容")
}
}
报错界面 ↓ :
报错原因:
这个错误的原因是 Scala 特质(trait)的初始化顺序问题。具体来说,FileLogger 特质中的 writer 初始化时,filename 还未被赋值(仍为 null),导致 FileWriter 构造器抛出 NullPointerException。
问题分析:
-
初始化顺序规则:当类继承特质时,特质的初始化先于子类。在你的代码中:
MyWriter类继承FileLogger特质。- 初始化
MyWriter时,会先初始化FileLogger特质。 - 特质初始化时会执行
val writer = new FileWriter(filename),但此时子类的filename("test.log")还未被赋值(特质中filename只是声明,未初始化),导致filename为null,进而FileWriter构造失败。
代码改正 ↓ :
package level02
import java.io.FileWriter
/*
*/
object class13 {
trait FileLogger{
println("fileLogger")
val filename:String
// 懒加载效果
// 这个对象不会立刻去创建,而是等到你需要使用的时候才去创建
lazy val writer = new FileWriter(filename)
def writeLog(msg:String): Unit = {
writer.write(msg)
writer.close()
}
}
class MyWriter extends FileLogger {
println("MyWriter")
override val filename: String = "test1.log"
} // 继承 三个特质A,B,C
def main(args: Array[String]): Unit = {
val log = new MyWriter()
log.writeLog("测试内容")
}
}