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());