避免NPE

在java开发中中NPE异常是常见异常,在阿里java开发手册中就明确强调防止NPE是调用者的责任是程序员基本修养,本篇博客先讲解NUll的知识点,随后讲解利用一些小技巧避免NPE

Null是什么

null是java中的关键字用来表示一些缺失的东西,null是所有引用类型的默认值,在这一部分强调几个关于null的知识点

1

null既不是对象也不是一种类型,它是一种特殊的值,你可以将null赋值任何引用类型,也可以将null强制转化为任何引用类型
如下

String str = (String) null;

强制转化过程编译器并不会报错

2

null的instanceof操作返回false

String str = null;
System.out.println(str instanceof String);

3

在java中null==null返回true

避免NPE

1.1equals方法

public void equals() {
    //代表未知的对象,可能会是NULL也可能不是NULL
    Object unKnowObject = null;
    //这样某些情况下可能会抛出NULLPointException
    System.out.println(unKnowObject.equals("str"));
    //改成如下
    //str一定不会空,所以不会抛出异常
    System.out.println("str".equals(unKnowObject));
}

1.2valueOf与toString

利用String.valueOf避免NPE

public void toMyString() {
    BigDecimal bigDecimal = null;
    //避免如下写法,当对象为空时候会抛出异常
    System.out.println(bigDecimal.toString());
    //使用String静态方法
    System.out.println(String.valueOf(bigDecimal));
}

1.3元素的list避免null

从数据库中检索数据如果结果集为空,利用0元素的list或者set来避免返回null

public void retrieveDataFromDB() {
    //如果没有检索到数据,返回0元素的list,map,set而不是null
    List result = Collections.EMPTY_LIST;
}

1.4拆箱与解包

下面这个例子是我们统计一个数字数组每个数字出现的次数
如下的写法是常见错误

public void unBox() {
    int[] array = {20, 5, 7, 5, 9, 2};
    final Map numCount = new HashMap<>();
    for (int v : array) {
        int result = numCount.get(v);
        numCount.put(v, ++result);
    }
    numCount.entrySet().stream().forEach(entry -> System.out.println(entry.getKey() + " -> " + entry.getValue()));
}

int result=numCount.get(v)取出的数据可能是null,而result是基本类型,对null进行拆箱自然就抛NPE异常了,所以get时需要进一步判断值是否是null

除了上面几种方法之外,我们还可以使用guava或者java8的Optional来避免NPE,下面主要讲解jdk中Optional使用

2.Optional

2.1初始化

初始化Optional有两种方法
1. of: of函数传入的参数不允许为null,否则抛出NullPointerException
2. ofNullable: ofNullable允许参数为空,创建一个不包含任何值得Optional值实例

Optional<String> name = Optional.of("wenruo");
Optional<String> nullableName = Optional.ofNullable(null);

2.2取数据

取数据时可以先isPresient判断是否有具体的数据,然后再get,不过get时候如果Optional没有数据就会抛异常

//isPresent函数有具体值得情况下返回true
if (name.isPresent()) {
    System.out.println(name.get());
}
//如果对空类型调用get会抛出异常
System.out.println(nullableName.get());

或者利用lambda表达式在实例有值的时候进行操作

//实例有值的情况下
name.ifPresent(value -> System.out.println(value));

2.3在无值情况下指定值

orElse和orElseGet可以在无值的情况下指定值,orElse可以无值的情况下指定字符串默认值
而orElseGet可以利用Supplier接口生成默认值

System.out.println(nullableName.orElse("* empty *"));
System.out.println(nullableName.orElseGet(() -> {
    int i = 5;
    return "default value";
}));

2.4值不存在的情况下抛自定义异常

自定义异常

private class ValueAbsentException extends Throwable {
    public ValueAbsentException() {
        super();
    }
    public ValueAbsentException(String message) {
        super(message);
    }
}

自定义在值不存在的情况下抛出指定异常

try {
    nullableName.orElseThrow(ValueAbsentException::new);
} catch (ValueAbsentException e) {
    e.printStackTrace();
    System.out.println("exception caught");
}

3.Optional扩展

3.1map

Optional还有其他的常用操作

//map可以返回任意类型
Optional upperName = name.map(value -> value.toUpperCase());
System.out.println(upperName.orElse("no value found"));

3.2flatMap

//flatMap返回值必须是Optional类型
name = name.flatMap((value) -> Optional.of(value.toUpperCase()));
System.out.println(name.orElse("No Value Found"));

3.3filter

Optional longName = name.filter(value -> value.length() > 10);
System.out.println(longName.orElse("the string length less than 10"));

你可能感兴趣的:(java)