1、JAVA8 之 Optional 详解

前言  

  相信不少小伙伴已经被java的NPE(Null Pointer Exception)所谓的空指针异常搞的头昏脑涨, 有大佬说过“防止 NPE,是程序员的基本修养。”但是修养归修养,也是我们程序员最头疼的问题之一,那么我们今天就要尽可能的利用Java8的新特性 Optional来尽量简化代码同时高效处理NPE(Null Pointer Exception 空指针异常)

认识 Optional

1、ofNullable 、orElse、isPresent 和 ifPresent

  Java 8 提供了判空写法:

Optional.ofNullable(对象).orElse(为空时的逻辑).ifPresent(不为空是的逻辑);
boolean isNull = Optional.ofNullable(对象).isPresent(); // 如果为空返回 false;不为空返回 true

  ofNullable 中的对象是一个可为空的对象(这个对象可以包含任意类型:Integer、Object、List、Map 等等),如果为空则执行 orElse 里面的逻辑,不为空则执行 ifPresent 里面的逻辑;也可以直接通过 isPresent() 来判断当前对象是否为空。直接上例子吧:

//求字符串 s 的长度( 为空的时候返回0 )
String str = getKey();
if (StringUtils.isBlank(str)) {
    return 0;
} else {
    return str.length();
}
// 新版 JDK 用法
return Optional.ofNullable(str).orElse("").length();
// 或者
if (Optional.ofNullable(str).isPresent()) {
    return str.length();
}
// 或者
Optional.ofNullable(str).ifPresent(s -> System.out.println("长度"+s.length());

  循环遍历List 集合

// 原来常规写法
List<String> list = getList();

if (list != null) {
  for(String s: list){
      System.out.println(s);
  }
}
// 新版 JDK 写法
Optional.ofNullable(list).orElse(new ArrayList<>()).forEach(o -> System.out.println(o));

2、filter

  用于对给定的对象进行过滤

  filter()方法大致意思是,接受一个对象,然后对他进行条件过滤,如果条件符合则返回Optional对象本身,如果不符合则返回空Optional

Person person=new Person();
person.setAge(2);
Optional.ofNullable(person).filter(p -> p.getAge()>50)

  再看一个根据基本的电子邮箱验证来决定接受或拒绝 User(用户) 的示例

@Test
public void whenFilter_thenOk() {
    User user = new User("anna@gmail.com", "1234");
    Optional<User> result = Optional.ofNullable(user)
      .filter(u -> u.getEmail() != null && u.getEmail().contains("@"));

    assertTrue(result.isPresent());
}

  如果通过过滤器测试,result 对象会包含非空值。

3、map

  map()方法将对应Funcation函数式接口中的对象,进行二次运算,封装成新的对象然后返回在Optional中

Person person1=new Person();
person.setAge(2);
// 返回具体内容
String optName = Optional.ofNullable(person).map(p -> person.getName()).orElse("name为空");
// 返回到 optional 中
Optional<Object> optName = Optional.ofNullable(person).map(p -> Optional.ofNullable(p.getName()).orElse("name为空"));

4、orElseThrow()

  这个我个人在实战中也经常用到这个方法,方法作用的话就是如果为空,就抛出你定义的异常,如果不为空返回当前对象,在实战中所有异常肯定是要处理好的,为了代码的可读性

//简单的一个查询
Member member = memberService.selectByPhone(request.getPhone());
Optional.ofNullable(member).orElseThrow(() -> new ServiceException("没有查询的相关数据"));

差异对比

1、orElse() 和 orElseGet() 的不同之处

  乍一看,这两种方法似乎起着同样的作用。然而事实并非如此。我们创建一些示例来突出二者行为上的异同。

@Test
public void givenEmptyValue_whenCompare_thenOk() {
    // 第一种情况
    User user = null;
    // 第二种情况
    User user = new User("john@gmail.com", "1234");
    logger.debug("Using orElse");
    User result = Optional.ofNullable(user).orElse(createNewUser());
    logger.debug("Using orElseGet");
    User result2 = Optional.ofNullable(user).orElseGet(() -> createNewUser());
}

private User createNewUser() {
    logger.debug("Creating New User");
    return new User("extra@gmail.com", "1234");
}

  打印输出结果如下:

// 第一种情况
Using orElse
creating user
Using orElseGet
creating user

// 第二种情况
Using orElse
creating user
Using orElseGet

  这个示例中,两个 Optional  对象都包含非空值,两个方法都会返回对应的非空值。不过,orElse() 方法仍然创建了 User 对象。与之相反,orElseGet() 方法不创建 User 对象。

  在执行较密集的调用时,比如调用 Web 服务或数据查询,这个差异会对性能产生重大影响

  且需要注意:orElse 内部可以直接写对应的方法或函数;orElseGet 内部必须要有对应的参数即使空也需要写一个空的括号,注意对比下:

User result = Optional.ofNullable(user).orElse(createNewUser());
User result2 = Optional.ofNullable(user).orElseGet(() -> createNewUser());

 

posted @ 2021-04-15 21:14  星火燎原智勇  阅读(2621)  评论(0编辑  收藏  举报