在Java8以前, 若是须要对一个变量作一次 null 检查, 一般会像下面这样写app
T t = service1.query(); if (t != null) { K k = service2.update(t); if (k != null) { U u = service3.save(k); } }
若是业务比较复杂, 可能会像上面那样, 使用 if 语句进行多层嵌套, 后期难以扩展。ide
在Java8中新引入了一个 Optional 类, Optional 类会对可能为 null 值的变量进行建模, 这样你就没必要直接将 null 赋值给变量, 也就没必要像上面那样进行多层嵌套检查。函数
在正式介绍 Optional 类的 API以前, 先引入一些实体类, 后面的代码示例会常常用到它们。测试
@Data public class Person { private Car car; private int age; public Optional<Car> getCar() { return Optional.ofNullable(car); } } @Data public class Car { private Insurance insurance; public Optional<Insurance> getInsurance() { return Optional.ofNullable(insurance); } } @Data public class Insurance { private String name; }
Optional 类提供了三种方式来建立 Optional 对象this
@Test public void test1() { //声明一个空的optional Optional<Car> c1 = Optional.empty(); //根据一个非空的值建立optional, 若是传入的值是null,会抛出空指针异常 Optional<Car> c2 = Optional.of(new Car()); //可接受null的Optional Optional<Object> c3 = Optional.ofNullable(null); }
flatMap()和map()都是在指定值存在时, 就对该值执行提供的 mapping 函数调用, 返回一个 Optional 类型的值, 不然就返回一个空的 Optional 对象。spa
注意 flatMap() 方法的转换函数是 Function<? super T, Optional<U>> mapper , 这个特性和前面介绍的 Stream 类的 flatMap() 很像。指针
查看一下 Optional 类的源码, flatMap() 会将 Optional<T> 中的 T 转换成 Optional<U>, 再将转换后的 Optional<U> 直接做为方法返回值返回。code
@Test public void test2() { Optional<Person> person = Optional.ofNullable(new Person()); String name = person.flatMap(Person::getCar).flatMap(Car::getInsurance).map(Insurance::getName).orElse("哪吒之魔童降世"); System.out.println(name); //result: 哪吒之魔童降世 }
上面的代码示例中, 由于 Person 实体类中 car 属性是一个 null 值, 因此 person.flatMap(Person::getCar) 这个操做会获得一个空的Optional 对象。orm
这样就致使了后面的 flatMap() 和 map() 两次转换都返回一个空的 Optional 对象。orElse() 方法的含义是若是有值则将其返回,不然返回一个默认值。因此最后的输出结果是默认值 哪吒之魔童降世 。对象
在实际业务中, 你能够像下面这样将 Optional 做为方法入参和返回值使用
@Test public void test3() { Optional<Insurance> insurance1 = find(Optional.of(new Person()), Optional.empty()); System.out.println(insurance1);//result: Optional.empty Optional<Insurance> insurance2 = find(Optional.of(new Person()), Optional.of(new Car())); System.out.println(insurance2);//result: Optional[Insurance(name=null)] } public Optional<Insurance> find(Optional<Person> person, Optional<Car> car) { return person.flatMap(p -> car.map(c -> find(p, c))); } private Insurance find(Person p, Car c) { return new Insurance(); }
@Test public void test4() { Optional.of("攀登者").filter(i -> i.length() < 4).ifPresent(System.out::println);//打印: 攀登者 Optional.<String>empty().filter(i -> i.length() < 4).ifPresent(System.out::println);//没有输出 }
下面是一个测试示例, 到本地去运行看下输出结果, 它能够帮你从新理解一下前面介绍的几个 API 的用法。
@Test public void test5() { System.out.println(getCarInsuranceName(Optional.empty(), 8));//result: 命运之夜 Person p = new Person(); p.setAge(10); System.out.println(getCarInsuranceName(Optional.of(p), 8));//result: 命运之夜 Insurance insurance = new Insurance(); insurance.setName("知否知否"); Car car = new Car(); car.setInsurance(insurance); p.setCar(car); System.out.println(getCarInsuranceName(Optional.of(p), 8));//result: 知否知否 } //找出年龄大于或者等于 minAge 参数的 Person 所对应的保险公司列表。 public String getCarInsuranceName(Optional<Person> person, int minAge) { return person.filter(p -> p.getAge() >= minAge).flatMap(Person::getCar).flatMap(Car::getInsurance).map(Insurance::getName).orElse("命运之夜"); }
一般在因为某种因素下, 函数没法正确返回某个值, 常见的作法就是使用 try/catch 语句处理返回一个null值, 或者不作任何处理直接抛出一个异常。
若是函数没法正确返回某个值, 且你不须要它抛出异常, 而是要它返回一个默认值, 那么 Optional 能够帮您更优雅的实现
@Test public void test6() { String value = "test"; Integer res = Optional.of(value).flatMap(this::str2Int).filter(i -> i > 0).orElse(0); System.out.println(res);//result: 0 } private Optional<Integer> str2Int(String str) { try { //若是能正确解析, 就将其封装在 Optional 中返回 return Optional.of(Integer.valueOf(str)); } catch (NumberFormatException ex) { //若是解析发生异常, 就返回一个空的 Optional return Optional.empty(); } }
上面的代码清单, Integer.valueOf() 会在入参不是一个整型数值时, 抛出 NumberFormatException , 咱们这里对它作了处理, 当解析发生异常时, 就返回一个空的 Optional 对象。
上面的用例只有在 value 变量是大于零的整型数值时, 才会输出 value 变量的值, 不然, 输出结果都是默认值 0。
最后, 来一张大图
做者:张小凡
出处:https://www.cnblogs.com/qingshanli/ 本文版权归做者和博客园共有,欢迎转载,但未经做者赞成必须保留此段声明,且在文章页面明显位置给出原文链接,不然保留追究法律责任的权利。若是以为还有帮助的话,能够点一下右下角的【推荐】。