空指针异常是导致java程序运行中断最常见的原因,相信每个程序猿都碰见过,也就是NullPointException,我们通常简称为NPE,本文告诉大家如何优雅避免NPE。
1.数据准备
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
|
package npe;
/\*\*
\* @author 百里
\*/
public class User {
private String name;
private int age;
private Address address;
public String getName() {
return name;
}
public void setName(String name) {
this.name \= name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age \= age;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address \= address;
}
public User(){
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
|
package npe;
/\*\*
\* @author 百里
\*/
public class Address {
private String street;
private String city;
private String country;
public Address(){
}
public Address(String street, String city, String country) {
this.street \= street;
this.city \= city;
this.country \= country;
}
// getters and setters
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street \= street;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city \= city;
}
|
UML类关系图:
2.实战:获取用户所在的城市
2.1.直接获取;容易出现空指针异常。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
/\*\*
\* 获取人员所在的城市
\* @author 百里
\*/
public class BaiLiNpeDemo {
public static void main(String\[\] args) {
Address myAddress \= new Address();
User myUser \= new User("John Doe", 35, myAddress);
String city \= myUser.getAddress().getCity().trim();
System.out.println(city);
}
}
|
2.2.使用if-else判断;避免了出现空指针的问题,但是代码结构层次嵌套多,不美观
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
|
/\*\*
\* 使用if进行判断
\* @author 百里
\*/
public class BaiLiSimpleNpeDemo {
public static void main(String\[\] args) {
Address myAddress \= new Address();
User myUser \= new User("John Doe", 35, myAddress);
if (myUser != null) {
Address address \= myUser.getAddress();
if (address != null) {
String city \= address.getCity();
if (city != null && !"".equals(city)) {
System.out.println("使用if判断字符串:" + "一键三连");
}
}
}
}
}
|
2.3.使用工具类美化一下if判断代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
|
/\*\*
\* 使用工具类
\* @author 百里
\*/
public class BaiLiUtilsNpeDemo {
public static void main(String\[\] args) {
Address myAddress \= new Address("123 Main St", " Austin ", "CA");
User myUser \= new User("John Doe", 35, myAddress);
//针对对象与字符串
if (!ObjectUtils.isEmpty(myUser)) {
Address address \= myUser.getAddress();
if (!ObjectUtils.isEmpty(address)) {
String city \= address.getCity();
if (!StringUtils.isEmpty(city)) {
System.out.println("使用StringUtils工具类判断字符串:" + "一键三连");
}
}
}
//针对数组使用工具类
ArrayList<User\> users \= new ArrayList<>();
users.add(myUser);
if (!CollectionUtils.isEmpty(users)) {
System.out.println("使用CollectionUtils工具类判断数组对象:" + "一键三连");
}
}
}
|
2.4.使用Optional解决了层次多的问题也避免了空指针的问题,当我们配合使用orElse时,会先执行orElse方法,然后执行逻辑代码,不管是否出现了空指针。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
|
/\*\*
\* 使用Optional
\* @author 百里
\*/
public class BaiLiOptionalNpeDemo {
public static void main(String\[\] args) {
Address myAddress \= new Address();
User myUser \= new User("John Doe", 35, myAddress);
System.out.println("使用Optional判断 + orElse:" +
Optional.ofNullable(myUser)
.map(User::getAddress)
.map(Address::getCity)
.map(String::trim)
.orElse(getDefaultCity())
);
}
//初始化城市
public static String getDefaultCity() {
System.out.println("初始化默认城市");
return null;
}
}
|
2.5.使用断言处理接口入参,检查假设和前置条件是否满足,以及检查空值情况,提前捕获空指针异常并进行处理
2.6.使用@Nullable注解,标识变量或方法参数和返回值是否可以为 null,以便在编译期或开发工具中提示可能的 NullPointerException 风险
2.7.额外补充
JDK17优化了空指针异常信息(Helpful NullPointerExceptions) 通过精确描述哪个变量为空来提高JVM生成的空指针异常信息的可用性。 即,以前的空指针异常信息不会告诉你具体是哪个对象为null,当运行的语句是对一个嵌套结构的对象做连续的方法调用(如”a.getb().getc().xxx()”)时,就需要进一步分析或调试才能判断出谁是null。而该特性加入以后则直接在异常信息中说明值为null的对象是哪个。
执行结果: