NPE 被抛出将 key/value 对加载到 java.util.Properties 对象中
NPE was thrown loading key/value pairs into java.util.Properties object
我 运行 遇到了一个问题,关于从流中将 key/value 对加载到 java.util.Properties 对象中,我自己很难回答。在我正在处理的 Foo servlet class 中有一个调用 loadProperties() 方法的方法。在情况 1) 中检索选定键的值有效,但在情况 2) loadProperties().getProperty("bar") 中抛出 NullPointerException。我不确定为什么会抛出 NPE。我忘了添加,但是在同一个 Foo 实例中多次调用了 loadProperties()。
案例 1)
public class Foo extends HttpServlet {
private InputStream is = null;
private Properties loadProperties() {
Properties p = new Properties();
is = Foo.class.getClassLoader().getResourceStream("/com/test/bar.properties");
p.load(is);
return p;
}
}
案例2)
public class Foo extends HttpServlet {
private final InputStream is = Foo.class.getClassLoader().getResourceStream("/com/test/bar.properties);
private Properties loadProperties() {
Properties p = new Properties();
p.load(is);
return p;
}
}
正在调用 loadProperties()
public class Foo extends HttpServlet {
private Properties loadProperties() { .... }
private void doSomething() {
PrintStream ps = new PrintStream(new FileOutputStream(loadProperties().getProperty("bar"))); // NPE was thrown in the case 2)
is.close();
}
private void doSomething2() {
PrintStream ps = new PrintStream(new FileOutputStream(loadProperties().getProperty("xyz")));
is.close();
}
}
[更新]
安迪回答了我的问题。当他问我 loadProperties() 是否调用了不止一次时,我检查了 Foo class 的长行,唉!我发现它在 doPost 方法中无意中被调用了一次。
public class Foo extends HttpServlet {
protected void doPost(...) {
loadProperties();
callDoSomething();
callDoSomething2();
}
private Properties loadPropeties() {
....
}
private void doSomething() {
....
}
private void doSomething2() {
....
}
}
在情况 2 中,您试图在每次调用 loadProperties
方法时重新使用相同的流。
这 可能 在第一次调用时正常工作:Properties.load
将消耗流中的所有数据,直到到达末尾,然后返回所有它加载的Property
s。
(“可能”是因为下面提到的线程安全问题)
但是,在随后调用 loadProperties()
(情况 2)时,没有更多内容可读取 - 流中的所有数据都已被消耗。除非你明确地倒回流(你甚至可能做不到,这取决于返回的 InputStream
的特定子class),你将没有更多的数据可读。
然而,在情况 2 中还有另一个问题,这意味着您不应尝试倒带流:它不是线程安全的。如果两个线程试图同时调用 loadProperties()
,我不想猜测会发生什么。你可能只会胡说八道。
Properties.load(InputStream)
的 Javadoc 没有说明在传递的 InputStream
上同步的方法。因此,您应该避免陷入线程不安全代码的境地——在情况 1 中您就是这样做的,方法是为每次调用创建一个新的 InputStream
。
我假设您试图避免多次重新阅读属性。我建议在 class 之外加载 Properties
并将它们作为构造函数参数注入:
class Foo extends HttpServlet {
private final Properties properties;
Foo(Properties properties) {
this.properties = checkNotNull(properties);
}
private void doSomething() {
PrintStream ps = new PrintStream(new FileOutputStream(properties.getProperty("bar")));
// ...
}
这样,如果您有一个 Foo
的实例,它就具有有效的 Properties
;您不是在等待执行特定的代码路径,这将触发属性的加载,并且加载失败。
它还使代码更易于测试 - 您不再依赖于从文件加载的属性 - 它可以来自任何地方。
我 运行 遇到了一个问题,关于从流中将 key/value 对加载到 java.util.Properties 对象中,我自己很难回答。在我正在处理的 Foo servlet class 中有一个调用 loadProperties() 方法的方法。在情况 1) 中检索选定键的值有效,但在情况 2) loadProperties().getProperty("bar") 中抛出 NullPointerException。我不确定为什么会抛出 NPE。我忘了添加,但是在同一个 Foo 实例中多次调用了 loadProperties()。
案例 1)
public class Foo extends HttpServlet {
private InputStream is = null;
private Properties loadProperties() {
Properties p = new Properties();
is = Foo.class.getClassLoader().getResourceStream("/com/test/bar.properties");
p.load(is);
return p;
}
}
案例2)
public class Foo extends HttpServlet {
private final InputStream is = Foo.class.getClassLoader().getResourceStream("/com/test/bar.properties);
private Properties loadProperties() {
Properties p = new Properties();
p.load(is);
return p;
}
}
正在调用 loadProperties()
public class Foo extends HttpServlet {
private Properties loadProperties() { .... }
private void doSomething() {
PrintStream ps = new PrintStream(new FileOutputStream(loadProperties().getProperty("bar"))); // NPE was thrown in the case 2)
is.close();
}
private void doSomething2() {
PrintStream ps = new PrintStream(new FileOutputStream(loadProperties().getProperty("xyz")));
is.close();
}
}
[更新]
安迪回答了我的问题。当他问我 loadProperties() 是否调用了不止一次时,我检查了 Foo class 的长行,唉!我发现它在 doPost 方法中无意中被调用了一次。
public class Foo extends HttpServlet {
protected void doPost(...) {
loadProperties();
callDoSomething();
callDoSomething2();
}
private Properties loadPropeties() {
....
}
private void doSomething() {
....
}
private void doSomething2() {
....
}
}
在情况 2 中,您试图在每次调用 loadProperties
方法时重新使用相同的流。
这 可能 在第一次调用时正常工作:Properties.load
将消耗流中的所有数据,直到到达末尾,然后返回所有它加载的Property
s。
(“可能”是因为下面提到的线程安全问题)
但是,在随后调用 loadProperties()
(情况 2)时,没有更多内容可读取 - 流中的所有数据都已被消耗。除非你明确地倒回流(你甚至可能做不到,这取决于返回的 InputStream
的特定子class),你将没有更多的数据可读。
然而,在情况 2 中还有另一个问题,这意味着您不应尝试倒带流:它不是线程安全的。如果两个线程试图同时调用 loadProperties()
,我不想猜测会发生什么。你可能只会胡说八道。
Properties.load(InputStream)
的 Javadoc 没有说明在传递的 InputStream
上同步的方法。因此,您应该避免陷入线程不安全代码的境地——在情况 1 中您就是这样做的,方法是为每次调用创建一个新的 InputStream
。
我假设您试图避免多次重新阅读属性。我建议在 class 之外加载 Properties
并将它们作为构造函数参数注入:
class Foo extends HttpServlet {
private final Properties properties;
Foo(Properties properties) {
this.properties = checkNotNull(properties);
}
private void doSomething() {
PrintStream ps = new PrintStream(new FileOutputStream(properties.getProperty("bar")));
// ...
}
这样,如果您有一个 Foo
的实例,它就具有有效的 Properties
;您不是在等待执行特定的代码路径,这将触发属性的加载,并且加载失败。
它还使代码更易于测试 - 您不再依赖于从文件加载的属性 - 它可以来自任何地方。