我有一个类ValueRepository类,并希望在其中使用记录器。以下代码始终抛出NullPointerException。
public enum ValueRepository {
INSTANCE;
private static final Logger LOGGER = LoggerFactory.getLogger(ValueRepository.class.getName());
private Map<String, Set<String>> key2value;
private Map value2key;
ValueRepository() {
key2value = new HashMap();
value2key = new HashMap();
load("keyValue.txt");
}
public int size() {
return key2value.size();
}
public boolean hasKey(String key) {
return key2value.containsKey(key);
}
public boolean hasValue(String value) {
return value2key.containsKey(value);
}
public Set<String> getValues(String key) {
return key2value.get(key);
}
public String getKey(String value) {
return (String) value2key.get(value);
}
private void load(String filePath) {
BufferedReader br;
try {
br = IOUtils.fileReaderAsResource(filePath);
String line = null;
while ((line = br.readLine()) != null) {
LOGGER.info("test");
line = line.trim();
}
br.close();
} catch (IOException io) {
LOGGER.error("Can't load the file: " + filePath);
io.printStackTrace();
}
}
public static void main(String[] args) {
// do nothing
}
不应该这样做吗?
这个问题与链接有很大不同。它具体说明了为什么它不能在枚举器中用于枚举。
编辑:
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/Users/congmi/.m2/repository/org/apache/logging/log4j/log4j-slf4j-impl/2.6.2/log4j-slf4j-impl-2.6.2.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/Users/congmi/.m2/repository/org/slf4j/slf4j-log4j12/1.7.21/slf4j-log4j12-1.7.21.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.apache.logging.slf4j.Log4jLoggerFactory]
Exception in thread "main" java.lang.ExceptionInInitializerError
Caused by: java.lang.NullPointerException
at com.qe.repository.ValueRepository.load(ValueRepository.java:56)
at com.qe.repository.ValueRepository.<init>(ValueRepository.java:26)
at com.qe.repository.ValueRepository.<clinit>(ValueRepository.java:14)
Process finished with exit code 1
答案 0 :(得分:1)
因为您将ValueRepository
单身人士设计为enum
你有这个静态常量的初始化序列:
INSTANCE
(隐式调用构造函数)LOGGER
您需要将此初始化序列更改为:
LOGGER
INSTANCE
您无法使用enum
达到此序列,因为Java语法仍然存在
enum
个实例是第一个。
这意味着,您需要将单身作为普通class
实施,而不是enum
。
public class ValueRepository {
private static final Logger LOGGER = LoggerFactory.getLogger(ValueRepository.class.getName());
public static final ValueRepository INSTANCE = new ValueRepository();
// remaining code unchanged
}
答案 1 :(得分:0)
简答:在枚举中,静态LOGGER
变量为null,直到构造函数完成。有几种选择。
static
),LOGGER
(而是抛出异常)。 长答案:通常,枚举静态字段在构建实例之前无法解析,无论您是否拥有单例枚举或多个枚举条目。
这意味着只要你引用一个private static final
字段,它需要在实例构建期间运行另一段代码(也就是 - 不是字符串或原语),它将失败并显示NullPointerException
。
import java.util.Date;
public class HelloWorld{
public static void main(String []args){
System.out.println("Hello World");
final WierdEnum instance = WierdEnum.INSTANCE;
instance.printStuff();
}
static enum WierdEnum {
INSTANCE;
private static final String test = "hello";
private static final Date date = new Date();
WierdEnum() {
printStuff();
}
void printStuff() {
System.out.println("Static string: " + test);
System.out.println("Static date: " + date);
}
}
}
解析为:
$java -Xmx128M -Xms16M HelloWorld
Hello World
Static string: hello
Static date: null
Static string: hello
Static date: Mon Apr 16 18:57:27 UTC 2018
问题是类加载顺序导致在实例构造期间以null类变量结束。对于枚举而言,这是与类
不同的顺序我怀疑你想保留这个枚举,因为你将它用作单例模式,你可能在代码的其他地方有这种模式。您有几个选择:
1。删除static
,将记录器更改为实例而不是类变量。我们通常不会将实例变量用于记录器,因为它将为系统中的每个对象实例提供一个记录器。在这种情况下,只有一个!所以没问题。
private final Logger LOGGER = LoggerFactory.getLogger(ValueRepository.class);
2。或者在施工期间不要使用记录仪。如果在读取文件时出现问题,请抛出新的异常,而不是记录。我怀疑这是可取的,因为看起来你不能从失败的文件读取中恢复。
} catch (IOException io) {
throw new RuntimeException("Can't load the file: " + filePath, io);
}
3. 将数据加载到静态初始化程序块中的静态字段中。
private static Map<String, Set<String>> key2value = new HashMap<>();
private static Map value2key = new HashMap();
static {
load("keyValue.txt");
}
private static void load(String filePath) {
...