Java NullPointerException - 检测、修复和最佳实践

java.lang.NullPointerException是最流行的Java程序(/社区/教程/例外处理-in-Java)编程之一.任何在Java工作的人都必须在Java独立程序以及JavaWeb应用程序(/社区/教程/javaweb-application-tutorial-for-beginners)中的任何地方都看到这种出现。

java.lang.NullPointer例外

java lang nullpointerexception hierarchy

NullPointerException是一个运行时间的例外,所以我们不需要在程序中捕捉它。NullPointerException在我们试图在 null上执行某些操作时在应用程序中提出。

  1. 在对象实例中调用方法,但在运行时对象为 null. 2.在运行时访问对象实例的变量为 null. 3.在程序中扔 null 4.访问指数或修改数组的指数值为 null 5.检查在运行时为 null的数组的长度

Java NullPointer例外

让我们来看看Java程序中的NullPointerException的几个例子。

1. NullPointerException 在调用实例方法时

 1public class Temp {
 2
 3    public static void main(String[] args) {
 4
 5    	Temp t = initT();
 6    	
 7    	t.foo("Hi");
 8    	
 9    }
10
11    private static Temp initT() {
12    	return null;
13    }
14
15    public void foo(String s) {
16    	System.out.println(s.toLowerCase());
17    }
18}

当我们运行上述程序时,它会扔下面的 NullPointerException 错误消息。

1Exception in thread "main" java.lang.NullPointerException
2    at Temp.main(Temp.java:7)

我们在声明 t.foo(Hi); 中得到 NullPointerException,因为t在这里为 null。

2. Java NullPointerException 在访问/修改 null 对象的字段时

 1public class Temp {
 2
 3    public int x = 10;
 4    
 5    public static void main(String[] args) {
 6
 7    	Temp t = initT();
 8    	
 9    	int i = t.x;
10    	
11    }
12
13    private static Temp initT() {
14    	return null;
15    }
16
17}

上面的程序会扔下面的 NullPointerException 堆栈痕迹。

1Exception in thread "main" java.lang.NullPointerException
2    at Temp.main(Temp.java:9)

NullPointerException 在声明中被扔到 int i = t.x;,因为t在这里为 null。

Java NullPointerException 当 null 在方法参数中被传递时

 1public class Temp {
 2
 3    public static void main(String[] args) {
 4
 5    	foo(null);
 6
 7    }
 8
 9    public static void foo(String s) {
10    	System.out.println(s.toLowerCase());
11    }
12}

这是java.lang.NullPointerException最常见的出现之一,因为它是通过 null 参数的召唤者。

下面的图像显示在 Eclipse IDE 中运行上述程序时的 null 指针例外。

Exception in thread main java.lang.NullPointerException

4. java.lang.NullPointer 当 null 被扔掉时的例外

1public class Temp {
2
3    public static void main(String[] args) {
4
5    	throw null;
6    }
7
8}

下面是上面的程序的例外堆栈跟踪,显示 NullPointerException 因为扔 null; 声明。

1Exception in thread "main" java.lang.NullPointerException
2    at Temp.main(Temp.java:5)

5. NullPointerException 在获取 null 数列的长度时

 1public class Temp {
 2
 3    public static void main(String[] args) {
 4
 5    	int[] data = null;
 6    	
 7    	int len = data.length;
 8    }
 9
10}
1Exception in thread "main" java.lang.NullPointerException
2    at Temp.main(Temp.java:7)

访问 null 数组的索引值时的 NullPointerException

 1public class Temp {
 2
 3    public static void main(String[] args) {
 4
 5    	int[] data = null;
 6    	
 7    	int len = data[2];
 8    }
 9
10}
1Exception in thread "main" java.lang.NullPointerException
2    at Temp.main(Temp.java:7)

7. NullPointerException 当同步到 null 对象时

 1public class Temp {
 2
 3    public static String mutex = null;
 4    
 5    public static void main(String[] args) {
 6
 7    	synchronized(mutex) {
 8    		System.out.println("synchronized block");
 9    	}		
10    }
11}

同步(mutex)将丢弃NullPointerException,因为mutex对象为null。

8. HTTP 状态 500 java.lang.NullPointerException

有时,我们会收到一个错误页面的响应(社区/教程/java-web-application-tutorial-for-beginners)与一个错误消息,如HTTP 状态 500 – 内部服务器错误和根源原因为java.lang.NullPointerException

为此,我编辑了 [春季MVC示例]( / 社区 / 教程 / 春季MVC示例)项目,并如下所示更改了HomeController方法。

1@RequestMapping(value = "/user", method = RequestMethod.POST)
2    public String user(@Validated User user, Model model) {
3    	System.out.println("User Page Requested");
4    	System.out.println("User Name: "+user.getUserName().toLowerCase());
5    	System.out.println("User ID: "+user.getUserId().toLowerCase());
6    	model.addAttribute("userName", user.getUserName());
7    	return "user";
8    }

下面的图像显示了 Web 应用程序响应投放的错误消息。

http error 500 java lang nullpointerexception

以下是例外 Stack Trace:

 1HTTP Status 500  Internal Server Error
 2
 3Type Exception Report
 4
 5Message Request processing failed; nested exception is java.lang.NullPointerException
 6
 7Description The server encountered an unexpected condition that prevented it from fulfilling the request.
 8
 9Exception
10
11org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.NullPointerException
12    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:982)
13    org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872)
14    javax.servlet.http.HttpServlet.service(HttpServlet.java:661)
15    org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
16    javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
17    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
18Root Cause
19
20java.lang.NullPointerException
21    com.journaldev.spring.controller.HomeController.user(HomeController.java:38)
22    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
23    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
24    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
25    java.lang.reflect.Method.invoke(Method.java:498)

根源原因在声明 user.getUserId().toLowerCase() 中为 NullPointerException,因为 user.getUserId() 返回 null。

如何检测 java.lang.NullPointerException

检测 NullPointerException 非常简单,只需看看例外痕迹,它会向您显示例外的类名称和行号码。然后看看代码,看看什么可能导致 NullPointerException。

如何修复 NullPointerException

java.lang.NullPointerException是一个未经检查的例外,所以我们不必抓住它. null指针例外可以使用 null检查和预防性编码技术来防止。

1if(mutex ==null) mutex =""; //preventive coding
2    	
3synchronized(mutex) {
4    System.out.println("synchronized block");
5}
1//using null checks
2if(user!=null && user.getUserName() !=null) {
3System.out.println("User Name: "+user.getUserName().toLowerCase());
4}
5if(user!=null && user.getUserName() !=null) {
6    System.out.println("User ID: "+user.getUserId().toLowerCase());
7}

编码最佳实践以避免 NullPointerException

让我们考虑下面的函数,看看导致 null 指针例外的场景。

1public void foo(String s) {
2    if(s.equals("Test")) {
3    System.out.println("test");
4    }
5}

NullPointerException 可能会发生,如果参数被传递为 null. 可以写下面的相同方法来避免 NullPointerException。

1public void foo(String s) {
2    if ("Test".equals(s)) {
3    	System.out.println("test");
4    }
5}

我们还可以为参数添加 null 检查,并在需要时扔IllegalArgumentException

1public int getArrayLength(Object[] array) {
2    
3    if(array == null) throw new IllegalArgumentException("array is null");
4    
5    return array.length;
6}

我们可以使用如下示例代码中所示的三级运算器。

1String msg = (str == null) ? "" : str.substring(0, str.length()-1);

使用String.valueOf()而不是toString()方法,例如检查 PrintStream println() 方法代码定义如下。

1public void println(Object x) {
2        String s = String.valueOf(x);
3        synchronized (this) {
4            print(s);
5            newLine();
6        }
7    }

下面的代码片段显示了使用 valueOf() 方法而不是 toString() 的示例。

1Object mutex = null;
2
3//prints null
4System.out.println(String.valueOf(mutex));
5
6//will throw java.lang.NullPointerException
7System.out.println(mutex.toString());

5、在可能的情况下,写出返回空对象而不是null的方法,例如空列表、空字符串等。

若要避免 NullPointerException,您应该使用某些方法,例如包含(),包含Key(),并包含Value()。

参考: API 文档

Published At
Categories with 技术
Tagged with
comments powered by Disqus