枚举Logger

时间:2018-03-06 23:55:48

标签: java log4j

我有一个类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

2 个答案:

答案 0 :(得分:1)

因为您将ValueRepository单身人士设计为enum 你有这个静态常量的初始化序列:

  1. INSTANCE(隐式调用构造函数)
  2. LOGGER
  3. 您需要将此初始化序列更改为:

    1. LOGGER
    2. INSTANCE
    3. 您无法使用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,直到构造函数完成。有几种选择。

  1. 使记录器成为实例变量(删除static),
  2. 在施工期间不要引用LOGGER(而是抛出异常)。
  3. 将数据加载到静态初始化程序块中的静态字段中,而不是在构造函数中。
  4. 长答案:通常,枚举静态字段在构建实例之前无法解析,无论您是否拥有单例枚举或多个枚举条目。

    这意味着只要你引用一个private static final字段,它需要在实例构建期间运行另一段代码(也就是 - 不是字符串或原语),它将失败并显示NullPointerException

    请参阅此example in action here

    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) {
    ...