所谓空指针:就是java中对象的引用为null,string、list、map、类的对象等,初始化或调用其他类得到的结果都可能为null。写java程序时要特别注意空指针对象的引用。这类错误发生的比例很高,一般容易察觉。
最近碰到一个奇怪的问题,在一个类(类名MyHandler)中有类似初始化:
private static MyConstruct myconstruct = new MyConstruct();
MyConstruct是自己写的一个类,里面有一些初始化,异常捕捉,对外提供公用方法。但是该类的初始化依赖配置文件,可能会忘配,所以初始化时可能会抛出空指针异常。
MyHandler类的调用是通过一个线程去调用,线程中捕捉了Exception。配置文件忘写时,表现的现象就是线程一直在初始化,但从未正常执行。最后检查问题发现是MyConstruct初始化有问题,但是异常信息没有被抛出。
写了一个测试类,抛出算法异常:
public class testException { private static final int k = 1/ 1; public static void main(String[] args) { try { testError error = new testError(); System.out.println("haha init success"); } catch (NullPointerException e) { System.out.println("testError throw null point exception"); }catch (Exception e) { System.out.println("get exception"); } } } class testError { public static int i = 0; public static int j = 1 / 0; static { try { j = 1 / 1; } catch (Exception e) { System.out.println("testError throw exception"); } } public void print() { System.out.println(j); } }
运行信息:
Exception in thread "main" java.lang.ExceptionInInitializerError
at testException.main(testException.java:12)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
Caused by: java.lang.ArithmeticException: / by zero
at testError.<clinit>(testException.java:25)
... 6 more
Process finished with exit code 1
如果static初始化变量时抛出NullPointerException,程序是不能正常捕捉到的,直接运行时退出。
如果程序改成如下:
public class testException { private static final int k = 1/ 1; public static void main(String[] args) { try { testError error = new testError(); System.out.println("haha init success"); } catch (NullPointerException e) { System.out.println("testError throw null point exception"); }catch (Exception e) { System.out.println("get exception"); } } } class testError { public static int i = 0; public static int j = 1 / 1; static { try { j = 1 / 0; } catch (Exception e) { System.out.println("testError throw exception"); } } public void print() { System.out.println(j); } }
运行信息:
testError throw exceptionhaha init success
结论:
写java程序时要尽量避免NullPointerException,少使用static变量初始化(除非你确定这种初始化不会有异常,不然很难发现祸根),在程序中有可能有异常发生的地方要try catch,这样可以减少排查问题的时间。