Search code examples
javaloggingstatic-initialization

Java final static field is null at first usage


There is a class which should store logs in a local file, which is hardcoded into the program.

The logic for initializing it as follows:

import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.io.IOException;

public class Util {
    private static final Logger LOGGER = Logger.getLogger(Util.class.getName());
    private static final FileHandler filehandler = createFileHandler();

    private static FileHandler createFileHandler(){
        FileHandler handler;
        try {
            handler = new FileHandler("security.log", 0, 1, true);
            LOGGER.addHandler(filehandler);
        } catch (IOException | SecurityException e) {
            handler = null;
            LOGGER.log(Level.SEVERE, "Unable to create Security log!");
        }
        return handler;
    }
    
    public static String use_util(){
        LOGGER.log(Level.INFO, "Utils are used!");
        return "It's just I don't know.. a string, man.";
    }
    
    public static void main(String[] args){
        System.out.println(Util.use_util());
    }
}

Upon the first call of use_util there is a nullpointerexception however, stating that LOGGER is null:

$javac Util.java
$java -Xmx128M -Xms16M Util
Exception in thread "main" java.lang.ExceptionInInitializerError
Caused by: java.lang.NullPointerException
    at java.util.logging.Logger.addHandler(Logger.java:1748)
    at Util.createFileHandler(Util.java:14)
    at Util.<clinit>(Util.java:8)

According to the Java spec section 12.4.2 :

Then, initialize the final class variables and fields of interfaces whose values are compile-time >constant expressions (§8.3.2.1, §9.3.1, §13.4.9, §15.28). ...

Next, execute either the class variable initializers and static initializers of the class, or the field >initializers of the interface, in textual order, as though they were a single block.

So based on that, LOGGER should be initialized before fileHandler is. Despite that, LOGGER seems to be null when the fileHandler is initialized...

Why is that? How can the initialization order be forced?


Solution

  • Caused by: java.lang.NullPointerException
    
    at java.util.logging.Logger.addHandler(Logger.java:1748)
    

    From the way I read this, the class fields are not an issue here. LOGGER is not null, the call towards LOGGER.addHandler() is executed, but fails internally.

    This is because you pass filehandler into the call, not the handler handler that you just initialized in the line before. Since you're still within the initialization execution for filehandler at that point, it is still null.