下载JDK14
如果下载速度太慢,还可以去这个 国内镜像站 下载。
解压,配置环境变量
略。
配置好之后在命令行用 java -version 验证,确保当前用的是 JDK14 版本,示例输出如下:
~$ java -version
openjdk version "14" 2020-03-17
OpenJDK Runtime Environment (build 14+36-1461)
OpenJDK 64-Bit Server VM (build 14+36-1461, mixed mode, sharing)
复制代码
编写会抛出空指针异常的代码
Hello.java 内容如下:
public class Hello{
public static void main(String[] args){
// write your code here
Person p = new Person();
p.firstName = "Wenjian";
p.lastName = null;
String upperLastName = p.lastName.toUpperCase();
String fullName = p.firstName + upperLastName;
System.out.println("full name = " + fullName);
}
static class Person{
public String firstName;
public String lastName;
}
}
复制代码
编译并执行
在命令行窗口执行:
javac Hello.java
java -XX:+ShowCodeDetailsInExceptionMessages Hello
复制代码
显示的错误信息如下:
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.toUpperCase()" because ".lastName" is null
at Hello.main(Hello.java:8)
复制代码
从这个信息中不仅能看出异常是在 Hello.java 的第 8 行出现的,还能知道是由于 .lastName 这个变量为空,所以在执行 String.toUpperCase() 方法时导致的这个异常。
其中:
就是指的这个方法中声明的 第1个 local 变量,即 Person p = new Person()
接下来我们把变量 p 赋值为 null,即程序改成如下:
public class Hello{
public static void main(String[] args){
// write your code here
Person p = null;
p.firstName = "Wenjian";
p.lastName = null;
String upperLastName = p.lastName.toUpperCase();
String fullName = p.firstName + upperLastName;
System.out.println("full name = " + fullName);
}
static class Person{
public String firstName;
public String lastName;
}
}
复制代码
重新编译并执行之后,错误信息如下:
Exception in thread "main" java.lang.NullPointerException: Cannot assign field "firstName" because "" is null
at Hello.main(Hello.java:6)
复制代码
同样的指出了在第 6 行,由于 这个变量是 null, 所以在给它的 firstName 字段赋值时抛出了空指针异常,非常清晰。
另外,你可能注意到了,在我们执行程序时,加上了一个参数: -XX:+ShowCodeDetailsInExceptionMessages, 这是因为 JEP358 这个特性虽然在 JDK14 中已经引入,但是没有默认启用,需要在执行时加入这个参数来输出详细的空指针异常信息。
在 JDK15 版本中,这个特性将被默认设置成启用。
The feature can be toggled with the new boolean command-line option -XX:{+|-}ShowCodeDetailsInExceptionMessages. The option will first have default 'false' so that the message is not printed. It is intended to enable code details in exception messages by default in a later release.
20200424,补充:
在执行 javac Hello.java 的时候添加 -g 参数,可以将提示信息的 显示为代码中实际的变量名称,对调试更加友好。
如:
javac Hello.java
java -XX:+ShowCodeDetailsInExceptionMessages Hello
Exception in thread "main" java.lang.NullPointerException: Cannot assign field "firstName" because "p" is null
at Hello.main(Hello.java:6)
复制代码
原理是:如果编译的时候加入了 -g 参数,javac 会把变量名字写入到 .class 文件中去。