Java基础干货12种方法让你彻底告别空指针异常

Posted 在路上的德尔菲

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java基础干货12种方法让你彻底告别空指针异常相关的知识,希望对你有一定的参考价值。

🤔What 什么是空指针NullPointerException(NPE)

空指针是运行时异常,所以就导致在编码时不易发现,因为Java中对象可以设为null,当去使用为null的对象操作时会抛出空指针,NullPointerException 官方解释👇

NullPointerException is a RuntimeException. In Java, a special null value can be assigned to an object reference. NullPointerException is thrown when an application attempts to use an object reference that has the null value. These include:

  • Calling the instance method of a null object.
  • Accessing or modifying the field of a null object.
  • Taking the length of null as if it were an array.
  • Accessing or modifying the slots of null as if it were an array.
  • Throwing null as if it were a Throwable value.
public class NullPointerException extends RuntimeException {
    private static final long serialVersionUID = 5162710183389028792L;

    public NullPointerException() {
        super();
    }
    public NullPointerException(String s) {
        super(s);
    }
}

😲Why 为什么要避免

公司内部 CaseStudy 平台有很多空指针引起的事故,其中一个涉及金额为1,819,172元,退款订单数1662,客诉50+,一行代码可以造成这么大的影响…

可以说这是一个编程中出现最频繁的bug,有人说70%以上的异常都是NullPointerException

如果编码不小心,可能会造成很大的损失,但只要养成好的编码习惯,NPE就不会出现

😈How 消灭NPE

1、已知对象放前

总是从已知的非空String对象中调用equals()方法,equals()方法是对称的,a.equals(b)与b.equals(a)是完全相同的,这是避免空指针的最常见的技巧

//错误方式❌
if(ObjectA.equals("ObjectB")){
	 .....
}
//正确方式✅
if(”ObjectB“.equals(ObjectA)){
	 .....
}
//正确方式✅
Boolean.TRUE.equals(a);

2、对象判空

Objects.equals(obj1,obj2);

-------------------------------------------
public static boolean equals(Object a, Object b) {
   return (a == b) || (a != null && a.equals(b));
}

3、使用contains()/containsKey()/containsValue()时注意

HashMap<Object, Object> map = null;
//错误示范❌
Object test = map.get("test");
//错误示范❌
if (map.containsKey("test")){
    System.out.println(map.get("test"));
}

4、使用 concat()/trim()时注意

String str = null;
//错误示范❌
str.concat("hello");
//错误示范❌
str.trim();

5、valueOf()与toString()返回相同结果时,使用前者

调用null对象的toString()会抛出空指针异常,而使用valueOf()可以获得相同的值,传递一个null给valueOf()将会返回null,Integer,Double,BigDecimal

String s = null;
//错误方式❌
System.out.println(s.toString());
//正确方式✅
System.out.println(String.valueOf(s)); 

----------------------------------
public static String valueOf(Object obj) {
     return (obj == null) ? "null" : obj.toString();
}

6、不必要的自动包装和自动解包

如果wrapper类对象是null,自动包装同样容易导致空指针异常,以及int 与Integer类型

public class Student {
    private Integer age;
    private String name;

    public Student(String name) {
        this.name = name;
    }
    //setter and getter
}

Student student = new Student("ram");
// NullPointerException
int age = student.getAge();
// 返回null
Integer age = student.getAge();

7、使用工具类StringUtils,包括对null对象的判断

//使用工具库
System.out.println(StringUtils.isEmpty(null)); //true
System.out.println(StringUtils.isBlank(null)); //true
System.out.println(StringUtils.isNumeric(null)); //false
System.out.println(StringUtils.isAllUpperCase(null)); //false

8、先创建空集合

通过返回一个空的集合或者空数组,避免返回的是空集合而不是null,在确保调用size(),length()的时候不会因为返回的是null ,可用@NotNull 注解

Map emptyMap = Collections.EMPTY_MAP;
Set emptySet = Collections.EMPTY_SET;
List emptyList = Collections.EMPTY_LIST;

9、集合正确判空方式

Apache Commons Lang 包中CollectionUtils类可以帮助快速判空,集合可能为空

//错误方式❌
if(list.size() > 0){
   //do something
}

if(CollectionUtils.isEmpty(list)){
		//do something
}
-------------------------------------------
public static boolean isEmpty(Collection coll) {
   return (coll == null || coll.isEmpty());
}

10、对遍历的数组和集合进行判空

集合和数组可能为null,在进行遍历前先进行判空处理

Collection<Integer> myNumbers = buildNumbers();
//正确方式✅
if (CollectionUtils.isNotEmpty(myNumbers)) {
  for (Integer myNumber : myNumbers) {
    System.out.println(myNumber);
  }
}

11、Optional

一连串调用如obj.getA().getB().getC() ,容易出现NPE,且通过下面格式判断的话影响代码可读性,可使用Java 8 中Optional,感兴趣同学可自行搜索

if (user != null) {
    Address address = user.getAddress();
    if (address != null) {
        Country country = address.getCountry();
        if (country != null) {
            String isocode = country.getIsocode();
            if (isocode != null) {
                isocode = isocode.toUpperCase();
            }
        }
    }
}                

Optional目的是即保证程序健壮性的同时,又保持代码的优雅和可读性

String str= Optional.ofNullable(getMsgFormDB())                    
                .map(d->d.trim())                                  
                .map(d->d.replace(getMsgFromWebService()))         
                .map(d->d.trim())                                  
                .orElseGet(() -> Strings.EMPTY);  

12、监控报警

最后一点不是从代码层面上去消灭,但监控报警是防止空指针造成影响的最后一道防线,为了及时发现问题,一般设置NullPointerException > 1 就应该报警且报警级别高。

😀小结:

一写代码时思考清楚是否可能为空指针,二写完代码后认真检查一遍,三使用插件如 Alibaba Java Coding Guidelines 、FindBugs检查一遍

以上是关于Java基础干货12种方法让你彻底告别空指针异常的主要内容,如果未能解决你的问题,请参考以下文章

java中的空指针异常怎么解决

JAVA基础篇—异常

SpringBug记录 -- java.lang.NullPointerException在Spring单元测试中遇到的空指针异常及依赖注入异常总结

java的equals提示空指针异常

java空指针异常:java.lang.NullPointException

java hashmap空指针异常