认识Optional并使用

1、前言   相信不少小伙伴已经被java的npe(null pointer exception)所谓的空指针异常搞的头昏脑涨,有大佬说过“防止 npe,是程序员的基本修养。”但是修养归修养,也是我们程序员最头疼的问题之一,那么我们今天就要尽可能的利用java8的新特性 optional来尽量简化代码同时高效处理npe(null pointer exception 空指针异常)
2、认识optional并使用   简单来说,opitonal类就是java提供的为了解决大家平时判断对象是否为空用 会用 null!=obj 这样的方式存在的判断,从而令人头疼导致npe(null pointer exception 空指针异常),同时optional的存在可以让代码更加简单,可读性跟高,代码写起来更高效.
常规判断:
//对象 人//属性有 name,ageperson person=new person();if (null==person){     return person为null; }return person; 使用optional:
//对象 人//属性有 name,ageperson person=new person();return optional.ofnullable(person).orelse(person为null); 测试展示类person代码(如果有朋友不明白可以看一下这个):
public class person {    private string name;    private integer age;    public person(string name, integer age) {        this.name = name;        this.age = age;    }    public person() {    }    public string getname() {        return name;    }    public void setname(string name) {        this.name = name;    }    public integer getage() {        return age;    }    public void setage(integer age) {        this.age = age;    }} 下面,我们就高效的学习一下神奇的optional类!
2.1 optional对象创建 首先我们先打开optional的内部,去一探究竟 先把几个创建optional对象的方法提取出来
public final class optional {   private static final optional empty = new optional();   private final t value;   //我们可以看到两个构造方格都是private 私有的   //说明 我们没办法在外面去new出来optional对象   private optional() {        this.value = null;    }   private optional(t value) {        this.value = objects.requirenonnull(value);    }    //这个静态方法大致 是创建出一个包装值为空的一个对象因为没有任何参数赋值   public static optional empty() {        @suppresswarnings(unchecked)        optional t = (optional) empty;        return t;    }    //这个静态方法大致 是创建出一个包装值非空的一个对象 因为做了赋值   public static  optional of(t value) {        return new optional(value);    }    //这个静态方法大致是 如果参数value为空,则创建空对象,如果不为空,则创建有参对象   public static  optional ofnullable(t value) {        return value == null ? empty() : of(value);    } } 再做一个简单的实例展示 与上面对应
// 1、创建一个包装对象值为空的optional对象optional optempty = optional.empty();// 2、创建包装对象值非空的optional对象optional optof = optional.of(optional);// 3、创建包装对象值允许为空也可以不为空的optional对象optional optofnullable1 = optional.ofnullable(null);optional optofnullable2 = optional.ofnullable(optional); 我们关于创建optional对象的内部方法大致分析完毕 接下来也正式的进入optional的学习与使用中
2.2 optional.get()方法(返回对象的值) get()方法是返回一个option的实例值 源码:
public t get() {    if (value == null) {        throw new nosuchelementexception(no value present);    }    return value;} 也就是如果value不为空则做返回,如果为空则抛出异常 no value present 简单实例展示
person person=new person();person.setage(2);optional.ofnullable(person).get(); 2.3 optional.ispresent()方法(判读是否为空) ispresent()方法就是会返回一个boolean类型值,如果对象不为空则为真,如果为空则false 源码:
 public boolean ispresent() {        return value != null;    } 简单的实例展示:
person person=new person();person.setage(2);if (optional.ofnullable(person).ispresent()){//写不为空的逻辑system.out.println(不为空);}else{ //写为空的逻辑 system.out.println(为空);} 2.4 optional.ifpresent()方法(判读是否为空并返回函数) 这个意思是如果对象非空,则运行函数体 源码:
public void ifpresent(consumer consumer) {      //如果value不为空,则运行accept方法体      if (value != null)          consumer.accept(value);  } 看实例:
person person=new person();person.setage(2);optional.ofnullable(person).ifpresent(p -> system.out.println(年龄+p.getage())); 如果对象不为空,则会打印这个年龄,因为内部已经做了npe(非空判断),所以就不用担心空指针异常了
2.5 optional.filter()方法(过滤对象) filter()方法大致意思是,接受一个对象,然后对他进行条件过滤,如果条件符合则返回optional对象本身,如果不符合则返回空optional
源码:
public optional filter(predicate predicate) {    objects.requirenonnull(predicate);    //如果为空直接返回this    if (!ispresent())        return this;    else    //判断返回本身还是空optional        return predicate.test(value) ? this : empty();} 简单实例:
person person=new person();person.setage(2);optional.ofnullable(person).filter(p -> p.getage()>50); 2.6 optional.map()方法(对象进行二次包装) map()方法将对应funcation函数式接口中的对象,进行二次运算,封装成新的对象然后返回在optional中 源码:
 public optional map(function mapper) {        objects.requirenonnull(mapper);        //如果为空返回自己        if (!ispresent())            return empty();        else {        //否则返回用方法修饰过的optional            return optional.ofnullable(mapper.apply(value));        }    } 实例展示:
person person1=new person();person.setage(2);string optname = optional.ofnullable(person).map(p -> person.getname()).orelse(name为空); 2.7 optional.flatmap()方法(optional对象进行二次包装) map()方法将对应optional函数式接口中的对象,进行二次运算,封装成新的对象然后返回在optional中 源码:
    public optional flatmap(function mapper) {        objects.requirenonnull(mapper);        if (!ispresent())            return empty();        else {            return objects.requirenonnull(mapper.apply(value));        }    } 实例:
person person=new person();person.setage(2);optional optname = optional.ofnullable(person).map(p -> optional.ofnullable(p.getname()).orelse(name为空)); 2.8 optional.orelse()方法(为空返回对象) 常用方法之一,这个方法意思是如果包装对象为空的话,就执行orelse方法里的value,如果非空,则返回写入对象 源码:
public t orelse(t other) {//如果非空,返回value,如果为空,返回other    return value != null ? value : other;} 实例:
person person1=new person();person.setage(2);optional.ofnullable(person).orelse(new person(小明, 2)); 2.9 optional.orelseget()方法(为空返回supplier对象) 这个与orelse很相似,入参不一样,入参为supplier对象,为空返回传入对象的.get()方法,如果非空则返回当前对象 源码:
    public t orelseget(supplier other) {        return value != null ? value : other.get();    } 实例:
optional sup=optional.ofnullable(person::new);//调用get()方法,此时才会调用对象的构造方法,即获得到真正对象optional.ofnullable(person).orelseget(sup.get()); 说真的对于supplier对象我也懵逼了一下,去网上简单查阅才得知 supplier也是创建对象的一种方式,简单来说,suppiler是一个接口,是类似spring的懒加载,声明之后并不会占用内存,只有执行了get()方法之后,才会调用构造方法创建出对象创建对象的语法的话就是supplier supperson= person::new;
需要使用时supperson.get()即可
2.10 optional.orelsethrow()方法(为空返回异常) 这个我个人在实战中也经常用到这个方法,方法作用的话就是如果为空,就抛出你定义的异常,如果不为空返回当前对象,在实战中所有异常肯定是要处理好的,为了代码的可读性
源码:
    public  t orelsethrow(supplier exceptionsupplier) throws x {        if (value != null) {            return value;        } else {            throw exceptionsupplier.get();        }    } 实例:这个就贴实战源码了
//简单的一个查询member member = memberservice.selectbyphone(request.getphone());optional.ofnullable(member).orelsethrow(() -> new serviceexception(没有查询的相关数据)); 2.11 相似方法进行对比分析 可能小伙伴看到这,没用用过的话会觉得orelse()和orelseget()还有orelsethrow()很相似,map()和flatmap()好相似
哈哈哈不用着急,都是从这一步过来的,我再给大家总结一下不同方法的异同点
orelse()和orelseget()和orelsethrow()的异同点
方法效果类似,如果对象不为空,则返回对象,如果为空,则返回方法体中的对应参数,所以可以看出这三个方法体中参数是不一样的
orelse(t 对象) orelseget(supplier 对象) orelsethrow(异常) map()和orelseget的异同点
方法效果类似,对方法参数进行二次包装,并返回,入参不同
map(function函数) flatmap(optional函数) 具体要怎么用,要根据业务场景以及代码规范来定义,下面可以简单看一下我在实战中怎用使用神奇的optional
3、实战场景再现
  场景1:在service层中 查询一个对象,返回之后判断是否为空并做处理
 //查询一个对象 member member = memberservice.selectbyidno(request.getcertificateno()); //使用ofnullable加orelsethrow做判断和操作 optional.ofnullable(member).orelsethrow(() -> new serviceexception(没有查询的相关数据)); 场景2:我们可以在dao接口层中定义返回值时就加上optional 例如:我使用的是jpa,其他也同理
public interface locationrepository extends jparepository {optional findlocationbyid(string id);} 然后在是service中
public terminalvo findbyid(string id) {//这个方法在dao层也是用了optional包装了        optional terminaloptional = terminalrepository.findbyid(id);        //直接使用ispresent()判断是否为空        if (terminaloptional.ispresent()) {        //使用get()方法获取对象值            terminal terminal = terminaloptional.get();            //在实战中,我们已经免去了用set去赋值的繁琐,直接用beancopy去赋值            terminalvo terminalvo = beancopyutils.copybean(terminal, terminalvo.class);            //调用dao层方法返回包装后的对象            optional location = locationrepository.findlocationbyid(terminal.getlocationid());            if (location.ispresent()) {                terminalvo.setfullname(location.get().getfullname());            }            return terminalvo;        }        //不要忘记抛出异常        throw new serviceexception(该终端不存在);    } 实战场景还有很多,包括return时可以判断是否返回当前值还是跳转到另一个方法体中,什么的还有很多,如果大家没有经验的小伙伴还想进行学习,可以评论一下我会回复大家
4、optional使用注意事项
  optional真么好用,真的可以完全替代if判断吗?
我想这肯定是大家使用完之后optional之后可能会产生的想法,答案是否定的
举一个最简单的栗子:
例子1: 如果我只想判断对象的某一个变量是否为空并且做出判断呢?
person person=new person();person.setname();persion.setage(2);//普通判断if(stringutils.isnotblank(person.getname())){  //名称不为空执行代码块}//使用optional做判断optional.ofnullable(person).map(p -> p.getname()).orelse(name为空); 我觉得这个例子就能很好的说明这个问题,只是一个很简单判断,如果用了optional我们还需要考虑包装值,考虑代码书写,考虑方法调用,虽然只有一行,但是可读性并不好,如果别的程序员去读,我觉得肯定没有if看的明显
5、jdk1.9对optional优化
首先增加了三个方法:
or()、ifpresentorelse() 和 stream()。 or() 与orelse等方法相似,如果对象不为空返回对象,如果为空则返回or()方法中预设的值。 ifpresentorelse() 方法有两个参数:一个 consumer 和一个 runnable。如果对象不为空,会执行 consumer 的动作,否则运行 runnable。相比ifpresent()多了orelse判断。 stream() 将optional转换成stream,如果有值就返回包含值的stream,如果没值,就返回空的stream。
因为这个jdk1.9的optional具体我没有测试,同时也发现有蛮好的文章已经也能让大家明白jdk1.9的option的优化,我就不深入去说了


电感镇流器电线发热如何解决
华为VoLTE解决方案可为用户提供丰富的业务体验
中南高科合肥智能制造产业园项目开工 项目总投资约10亿元
摩根大通建议苹果可以考虑巨资收购奈飞
vivo Z5x新机正式发布 颜值性能兼具
认识Optional并使用
构建一个基于RFID的非接触式温度监测系统
iphone8什么时候上市多少钱?iphone 8发布会时间确定,苹果8良心价6700起,买买买!
汽车电子电气系统的基础知识详解
串行总线和并行总线的区别
诺基亚9迭代版曝光 搭载骁龙855或在2019年8月发布
高容量嵌入式存储将与手机插槽展开竞争
浅谈微型扬声器粘接应用中无影胶逐渐取代溶剂胶水的原因
通过网络搭建零信任架构的方法
土壤测试仪能测试哪些项目
系统的信号输入中,键盘因其结构简单而被广泛使用
凯米斯低功耗在线浊度传感器的解决方案
OceanBase的简介,它与MySQL的比较
区块链技术将如何改变我们的生活?
未来Micro LED将走向混合式转移