问题描述
我有一个代码从文件加载属性:
I have this piece of code that loads Properties from a file:
class Config {
val properties: Properties = {
val p = new Properties()
p.load(Thread.currentThread().getContextClassLoader.getResourceAsStream("props"))
p
}
val forumId = properties.get("forum_id")
}
似乎工作正常。
我已经尝试将属性
的初始化移动到另一个val, loadedProperties
,像这样:
I have tried moving the initialization of properties
into another val, loadedProperties
, like this:
class Config {
val properties: Properties = loadedProps
val forumId = properties.get("forum_id")
private val loadedProps = {
val p = new Properties()
p.load(Thread.currentThread().getContextClassLoader.getResourceAsStream("props"))
p
}
}
但它不工作! (属性
在 properties.get(forum_id)
)中为空。
But it doesn't work! (properties
is null in properties.get("forum_id")
).
为什么会这样?当属性
引用时,不是 loadedProps
Why would that be? Isn't loadedProps
evaluated when referenced by properties
?
其次,这是一个很好的方法来初始化需要非平凡处理的变量吗?在Java中,我将声明它们 final
字段,并在构造函数中进行初始化相关的操作。
Secondly, is this a good way to initialize variables that require non-trivial processing? In Java, I would declare them final
fields, and do the initialization-related operations in the constructor.
在Scala中有这种情况的模式吗?
Is there a pattern for this scenario in Scala?
谢谢!
推荐答案
Vals会按照(正确地,非惰性 vals),因此属性
在 loadedProps
。或者换句话说,当属性
时, loadedProps
仍然是 null
正在初始化。
这里最简单的解决方案是在属性
之前定义 loadedProps
:
Vals are initialized in the order they are declared (well, precisely, non-lazy vals are), so properties
is getting initialized before loadedProps
. Or in other words, loadedProps
is still null
when properties
is getting initialized.The simplest solution here is to define loadedProps
before properties
:
class Config {
private val loadedProps = {
val p = new Properties()
p.load(Thread.currentThread().getContextClassLoader.getResourceAsStream("props"))
p
}
val properties: Properties = loadedProps
val forumId = properties.get("forum_id")
}
您也可以使 loadedProps
它将在其第一次访问时被初始化:
You could also make loadedProps
lazy, meaning that it will be initialized on its first access:
class Config {
val properties: Properties = loadedProps
val forumId = properties.get("forum_id")
private lazy val loadedProps = {
val p = new Properties()
p.load(Thread.currentThread().getContextClassLoader.getResourceAsStream("props"))
p
}
}
使用lazy val有一个优点,你的代码更强大的重构,因为只是改变你的vals的声明顺序不会破坏你的代码。
Using lazy val has the advantage that your code is more robust to refactoring, as merely changing the declaration order of your vals won't break your code.
在这种情况下,你只需将 loadedProps
转换为 def
(由@NIA建议)仍然使用一次。
Also in this particular occurence, you can just turn loadedProps
into a def
(as suggested by @NIA) as it is only used once anyway.
这篇关于Scala - vals的初始化顺序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!