您现在的位置是:首页 > 文章详情

java8学习:Optional的简单使用

日期:2018-11-21点击:339

内容来自《 java8实战 》,本篇文章内容均为非盈利,旨为方便自己查询、总结备份、开源分享。如有侵权请告知,马上删除。
书籍购买地址:java8实战

  • 如下代码

    public class Person { private Car car; public Car getCar() { return car; } } public class Car { private Insurance insurance; public Insurance getInsurance() { return insurance; } } public class Insurance{ private String name; public String getName() { return name; } } //将要使用的代码 public String getCarInsuranceName(Person person){ return person.getCar().getInsurance().getName(); }
  • 如上代码如果使用,如果某个Person没有车,那么就会引发空指针异常,在平常我们使用if来去判断的,比如

    public String getCarInsuranceName(Person person){ if (null != person){ Car car = person.getCar(); if (null != car){ Insurance insurance = car.getInsurance(); if (insurance != null) { return insurance.getName(); } } } return "UnKnow"; }
  • 或者更容易读的是这样的,避免了if的嵌套难以阅读

    public String getCarInsuranceName(Person person){ if (person == null) { return "UnKnow"; } Car car = person.getCar(); if (car == null){ return "UnKnow"; } Insurance insurance = car.getInsurance(); if (insurance == null) { return "UnKnow"; } return insurance.getName(); }
  • 如上null的解决办法使用中的,并且不容易阅读,java8使用了Optional来解决null问题

markdown_img_paste_20181122155551525

  • Optional只能包含一个对象,对象存在的时候,Optional只是对对象的简单封装,如果没有对象,那么缺失的值被建模成一个空的Optional对象,有方法Optional.empty()返回
  • null和Optional的区别:null一定会触发空指针异常,而Optional.empty()就没有事,因为他是一个有效对象,是Optional 的单一实例.
  • 使用Optional重新定义bean对象

    public class Person { private Optional<Car> car; public Optional<Car> getCar() { return car; } } public class Car { private Optional<Insurance> insurance; public Optional<Insurance> getInsurance() { return insurance; } } public class Insurance{ private String name; //公司肯定有名字 public String getName() { return name; } }
  • 上面中Person中的car类型是Optional,很明确的表达了Person可能有car对象也可能没有,同样对car的引用做了保证,有car的话就是car对象,没有car 的话就是Optional.empty()
  • Insurance中name并没有加Optional,因为公司肯定是有名字的,如果name为空只能代表参数是错误的,而这里如果加上Optional只能掩盖错误发生

Optional的创建

  • 空对象:Optional.empty()
  • 依靠一个非空对象创建Optional:Optional.of(notnullobj),如果notnullobj是一个空对象,那么就会抛出空指针异常
  • 可接受null对象的Optional:Optional.ofNullable(car),car对象可以是空对象也可以不是空对象,如果是空对象则得到一个空的Optional

使用map从Optional中提取和转换值

String name = null; if (insurance != null){ name = insurance.getName(); }
  • 如上是原来的提取的代码,先判断在取值,避免空指针,如下使用Optional

    Optional<String> name = Optional.ofNullable(insurance).map(Insurance::getName);
    • map函数会应用于流的每个元素上,然后返回name,可以把Optional看作是一个特殊的集合数据,至多包含一个元素,如果insurance包含值,那么就交给map处理,否则返回空Optional,就什么也不做
  • 本文开头提到的这样一连串的调用,怎么用Optional解决呢?

    //原来 public String getCarInsuranceName(Person person){ return person.getCar().getInsurance().getName(); }
    • 我们是用如下代码可不可以呢 ?
    public String getCarInsuranceName(Optional<Person> person){ person.map(Person::getCar) .map(Car::getInsurance) .map(Insurance::getName); }
    • 如上代码是编译通过不了的,因为person对象是一个Optional对象,那么他调用map将会返回一个Optional>,这显然是错误的
    • 之前我们在Stream遇到同样的问题,当时是用flatMap解决的,在这同样适用,如下
    public String getCarInsuranceName(Optional<Person> person){ return person.flatMap(Person::getCar) .flatMap(Car::getInsurance) .map(Insurance::getName) .orElse("Unknow"); }
    • 如上我们很清楚的就可以知道哪些对象可能是null,并且省去了if语句的平判断,在最后orElse:如果map得到的是null,那么就会有默认的UnKnow替代null,以防止发生空指针

Optional无法序列化

  • 为什么?

    • 如上代码中我们展示了使用Optional去构建bean,将允许缺失或者暂时无定义的变量值用特殊的形式标记出来,但是Optional的设计初衷并不是这样的,它的设计初衷仅仅是要支持能返回Optional的语法,由于它设计时就没有考虑将其作为类的字段使用,所以它也并未实现序列化接口,所以如果在框架或者序列化库中使用了 Optional修饰字段,那么可能会引发错误
    • 但是如上我们看到了,Optional应用到bean中也是不错的,能够清楚的反映出那些字段是有可能为null的,并且可以使用Optional的特性,可以这样在bean中应用Optional
    public class Car { private Insurance insurance; public Optional<Insurance> getInsuranceAsOptional() { return Optional.ofNullable(insurance); } }

使用filter剔除特定的值

  • 如果需要判断某个公司,那么我们需要这样的判断

    Insurance insurance = ...; if (null != insurance && "lalala".equals(insurance.getName())){ System.out.println("..."); }
  • 使用filter方法

    Optional<Insurance> insurance = null; insurance.filter(i -> "lalala".equals(i.getName())) .ifPresent(i -> System.out.println("..."));
    • 如上的ifPresent方法是判断i是否是空值,不是空值就执行后面的输出,是空即什么都不做

异常与Optional对象

  • String转换为Integer对象,如果转换错误就会爆数字格式化异常,我们必须try上异常以处理异常
  • 需求:输入参数转换为int,然后返回该转换后的值,出错的话就返回0

    public Integer StringParse(String str){ if (null == str) return 0; try { return Integer.parseInt(str); }catch (NumberFormatException e){ return 0; } }
  • 用Optional解决

    public Optional<Integer> StringParse(String str){ try { return Optional.of(Integer.parseInt(str)); }catch (NumberFormatException e){ return Optional.empty(); } }

避免使用基本类型的Optional对象

  • 对于之前的函数式接口,我们提到的如果基本类型比较多,那么就优先使用对应的基本类型的函数式接口,比如IntFunction,但是Optional不推荐使用OptionalInt等类似的基本类型对象,因为这些对象中并没有map和filter等方法
原文链接:https://yq.aliyun.com/articles/672570
关注公众号

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。

持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。

文章评论

共有0条评论来说两句吧...

文章二维码

扫描即可查看该文章

点击排行

推荐阅读

最新文章