java之空指针异常处理

空指针是我们 Java 开发人员经常遇到的一个基本异常,这是一个极其普遍但似乎又无法根治的问题。

本文将带你了解什么是空指针,以及如何有效的避免空指针。

什么是空指针?

当一个变量的值为 null 时,在 Java 里面表示一个不存在的空对象,没有实际内容,没有给它分配内存,null 也是对象成员变量的默认值。所以,一个对象如果没有进行初始化操作,这时候,如果你调用这个对象的方法或者变量,就会出现空指针异常。
如示例会发生空指针异常:


Object object = null;
String string = object.toString();

上述情况中,空指针它是属于运行时异常 RuntimeException 的子类,它不是捕获型的,在程序运行时随时可能报出来,而且会造成程序中断。

如何避免空指针

下面说几个空指针的几个最常见的案例及解决之道。

1、字符串比较,常量放前面


if(status.equals(SUCCESS)){

}

这个时候 status 可能为 null 造成空指针异常,应该把常量放前面,就能避免空指针异常。


if(SUCCESS.equals(status)){

}

2、初始化NULL,指定默认值


User user = NULL;
String name = NULL;

在对象初始化的时候给它一个默认值或者默认构造实现,如:


User user = new User();
String name = StringUtils.EMPTY;

3、返回值为NULL,返回空集合

在返回一个集合的话,默认会是 null,统一规范返回一个空集合。

举个 List 例子,如:

public List getUserList(){
    List list = userMapper.gerUserList();
    return list == null ? new ArrayList() : list;
}

这样接收方就不用担心空指针异常了,也不会影响业务。

4、断言

断言是用来检查程序的安全性的,在使用之前进行检查条件,如果不符合条件就报异常,符合就继续。

Java 中自带的断言关键字:assert,如:


assert name == null : “名称不能为空”;

Exception in thread “main” java.lang.AssertionError: 名称不正确
不过默认是不启动断言检查的,需要要带上 JVM 参数:-enableassertions 才能生效。

Java 中这个用的很少,建议使用 Spring 中的,更强大,更方便好用。

Spring中的用法:


Assert.notNull(name,“名称不能为空”);

5、Optional

Optional 是 JDK 8 新增的新特性,再也不用 != null 来判断了。


// book 存在则执行打印
Optional<Book> optBook = Optional.of(book);
optBook.ifPresent(book -> System.out.println(book.getName()));

// book 为NULL,则返回默认值
Optional<Book> optBook = Optional.of(book);
String bookName = optBook.orElse("Unknown");

// book 为NULL,则返回默认值
Optional<Book> optBook = Optional.of(book);
String bookName = optBook.orElse("Unknown");

你可以使用 of() 和 ofNullable() 方法创建包含值的 Optional。两个方法的不同之处在于如果你把 null 值作为参数传递进去,of() 方法会抛出 NullPointerException,而 ofNullable() 不会。

// user 对象是空的,则返回了作为默认值的 user2
@Test
public void whenEmptyValue_thenReturnDefault() {
    User user = null;
    User user2 = new User("anna@gmail.com", "1234");
    User result = Optional.ofNullable(user).orElse(user2);
 
    assertEquals(user2.getEmail(), result.getEmail());
}

// 存在即返回,无则提供默认值
return user.orElse(UNKNOWN_USER); //而不是 return user.isPresent() ? user.get() : null;

// 存在即返回, 无则由函数来产生
return user.orElseGet(() -> fetchAUserFromDatabase());

// 使用map
return user.map(u -> u.getOrders()).orElse(Collections.emptyList())

// 上面避免了类似 Java 8 之前的做法
if(user.isPresent()) {
	return user.get().getOrders();
} else {
	return Collections.emptyList();
}

// filter 如果有值并且满足断言条件返回包含该值的Optional,否则返回空Optional
@Test
public void useJava8() {
    List<Student> studentList = initData();
    for (Student student : studentList) {
        Optional<Student> studentOptional = Optional.of(student);
        // 如果年龄大于18则返回Student的Optional
        // 返回Score的Optional
        // Score为null则返回0
        Integer score = studentOptional.filter(s -> s.getAge() >= 18).flatMap(Student::getScore).orElse(0);
 
        if (score > 80) {
            System.out.println("入选:" + student.getName());
        }
    }
}

空值


Collections.emptyList();
StringUtils.EMPTY;

Optional 使用介绍
  1. 创建:

    Optional.empty(): 创建一个空的 Optional 实例

    Optional.of(T t):创建一个 Optional 实例,当 t为null时抛出异常

    Optional.ofNullable(T t):创建一个 Optional 实例,但当 t为null时不会抛出异常,而是返回一个空的实例

  2. 获取:

    get():获取optional实例中的对象,当optional 容器为空时报错

  3. 判断:

    isPresent():判断optional是否为空,如果空则返回false,否则返回true

    ifPresent(Consumer c):如果optional不为空,则将optional中的对象传给Comsumer函数

    orElse(T other):如果optional不为空,则返回optional中的对象;如果为null,则返回 other 这个默认值

    orElseGet(Supplier other):如果optional不为空,则返回optional中的对象;如果为null,则使用Supplier函数生成默认值other

    orElseThrow(Supplier exception):如果optional不为空,则返回optional中的对象;如果为null,则抛出Supplier函数生成的异常

  4. 过滤:

    filter(Predicate p):如果optional不为空,则执行断言函数p,如果p的结果为true,则返回原本的optional,否则返回空的optional

  5. 映射:

    map(Function<T, U> mapper):如果optional不为空,则将optional中的对象 t 映射成另外一个对象 u,并将 u 存放到一个新的optional容器中。

    flatMap(Function< T,Optional> mapper) 跟上面一样,在optional不为空的情况下,将对象t映射成另外一个optional

    区别:map会自动将u放到optional中,而flatMap则需要手动给u创建一个optional

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值