引发NullPointerException

时间:2018-09-27 10:37:04

标签: java exception nullpointerexception null synchronization

在几年前编写的一个Web服务器项目中,我偶尔会感到非常奇怪,并且-在我看来-不可能NullPointerException。 它发生在用于记录控制台输出的实用程序方法中。

这是该方法的错误摘录:

try {
    Encoder encoder = Base64.getEncoder();
    if(logWriter != null) {
        logWriter.write(String.valueOf(System.currentTimeMillis()));
        logWriter.write(" ");
        logWriter.write(String.valueOf(level));
        logWriter.write(" ");
        logWriter.write(encoder.encodeToString(Thread.currentThread().getName().getBytes()).replaceAll("(?:\\r\\n|\\n\\r|\\n|\\r)", ""));
        logWriter.write(" ");
        logWriter.write(encoder.encodeToString(log.getBytes()).replaceAll("(?:\\r\\n|\\n\\r|\\n|\\r)", ""));
        logWriter.write("\r\n");
        logWriter.flush();
    }

    lastWriterActivity = System.currentTimeMillis();
} catch (IOException e) {
    println("Failed to write log to file: " + e, Color.RED);

    try {
        logWriter.close();
    } catch (IOException e1) {
        println("### Possible resource leak; unable to close log writer", Color.RED);
    }

    logWriter = null;
}

其中logWriterBufferedWriter。 NPE被抛出到调用catch的第一个logWriter.close()块中。

但是:当logWriter是IOException时,如何在我的try块中抛出!= null呢? Base64.getEncoder()无法引发IOException,并且没有其他代码可以执行。

这是我的堆栈跟踪:

Exception in thread "connection_0:0:0:0:0:0:0:1@1544725509" java.lang.NullPointerException
at org.jpuzzle.main.Logger.write(Logger.java:347)
at org.jpuzzle.main.Logger.verbose(Logger.java:187)
at org.jpuzzle.protocol.http.HttpRequest.onRequest(HttpRequest.java:1090)
at org.jpuzzle.network.ConnectionListener$Connection.proceed(ConnectionListener.java:438)
at org.jpuzzle.network.ConnectionListener$Connection.run(ConnectionListener.java:408)

我的方法是synchronized,因此互斥应该没有任何困难,而且我不知道为什么会发生这种情况。

1 个答案:

答案 0 :(得分:2)

简短答案:

重写您的catch块,以避免出现NullPointerException

try {
  if(logWriter != null) {
    logWriter.close();
  }
} catch (IOException e1) {
    println("### Possible resource leak; unable to close log writer", Color.RED);
}

长答案:

  

是的,logWriter是静态的。   不同步是否会阻止方法并行执行方法?

否。

需要证明吗?

运行以下代码:

public class NowImFeelingZombified {
  static Object logWriter = new Object();

public static void main(String[] args) {
    final NowImFeelingZombified zombie1 = new NowImFeelingZombified();
    final NowImFeelingZombified zombie2 = new NowImFeelingZombified();

    Thread t1 = new Thread("zombie1 ") {
        @Override
        public void run() {
            zombie1.syncedMethod();
        }
    };
    Thread t2 = new Thread("zombie2 ") {
        @Override
        public void run() {
            zombie2.syncedMethod();
        }
    };
    t1.start();
    t2.start();
}

private synchronized void syncedMethod() {
    try {
        System.out.println(Thread.currentThread().getName() + logWriter.toString());

        Thread.sleep(2000L);

        System.out.println(Thread.currentThread().getName() + logWriter.toString());

        logWriter = null;
    }
    catch (InterruptedException e) {
    }
  }
}

输出是这样的:

zombie1 java.lang.Object@1c34796b
zombie2 java.lang.Object@1c34796b
zombie1 java.lang.Object@1c34796b
Exception in thread "zombie2 " java.lang.NullPointerException
    at NowImFeelingZombified.syncedMethod(NowImFeelingZombified.java:44)

Howsa?

同步方法将获得该方法的调用者的锁。含义t1不关心t2(当然也不关心logWriter)。

就是这样。在这里阅读full story

此外,很久以前,我为我一直使用的Util类编写了一个5衬里。它使我不必编写catch块来关闭Closeables

public static void close(Closeable closeable) {
    if (closeable != null) {
        try {
            closeable.close();
        }
        catch (IOException e) {
            //logging
        }
    }
}

无论如何,Java 1.7引入了您可能想探索的AutoCloseable(由BufferedWriter实现)。