• 为什么要使用Optional


    为什么使用Java Optional

    Why use Optional? NullPointerException

    有个很有名的说法: Null Pointer References: The Billion Dollar Mistake,这是发明null指针的人提出来的。(https://medium.com/@hinchman_amanda/null-pointer-references-the-billion-dollar-mistake-1e616534d485)

    为什么说空指针是十亿美元的错误,其实不光是java,在其他编程语言中,也经常会遇到空指针异常的问题。可以说这是一个编程中出现最频繁的bug,有人说70%以上的异常都是NullPointerException。我们可以看下代码:

    String str=new String("hello world");
    str.trim();
    

    如果我们只是写个简单的Demo,new一个简单对象,然后调用,当然ok, 不会有任何问题。但是一旦到了真实项目中,就会有很多问题,因为实际编程环境往往复杂得多,代码如下:

    String str=getMsgFormDB();
    str=str.trim();
    
    // 或者
    str=str.replace(getMsgFromWebService());
    str=str.trim();
    
    • 问题在哪里,哪一步会抛异常,抛出什么异常(不考虑调用方法抛出异常的情况)?

    通常会在str.trim()或str.append()这一步出现NullPointerException,因为str可能会是一个null值,而调用null对象的方法就是空指针异常了。

    那么我们一般是怎么那避免这个问题?如果有过一些实战经验的,不管用什么语言开发我们多少都会在踩坑培养出谨慎态度,哪就是不相信任何被调用的代码(包括自己写的方法),比如上面代码我们会这样写:

    String str=getMsgFormDB();
    
    if(null != str){
      str.trim();
      str=str.replace(getMsgFromWebService());
    }
    
    if(null != str){
      str= str.trim();
    }
    

    这样写,就保证了程序的健壮性,杜绝了NullPointerException。但是这就带来了一个问题,代码变得非常啰嗦,不可读性,想想看如果我们写一个比较复杂的业务,我们会写一堆非空检查,而且会层层嵌套,如:

    if (user != null) {
        Address address = user.getAddress();
        if (address != null) {
            Country country = address.getCountry();
            if (country != null) {
                String isocode = country.getIsocode();
                if (isocode != null) {
                    isocode = isocode.toUpperCase();
                }
            }
        }
    }
    

    那么有没有办法即保证程序健壮性的同时,又保持代码的优雅和可读性,Optional就是在java 8中提出的解决方案,看如下代码:

    String str= Optional.ofNullable(getMsgFormDB())                    //1
                    .map(d->d.trim())                                  //2
                    .map(d->d.replace(getMsgFromWebService()))         //3
                    .map(d->d.trim())                                  //4 
                    .orElseGet(() -> Strings.EMPTY);                   //5
    

    上面的这一行代码实际上是一个连续的调用链,使用了lambda表达式和Optional多个函数,我们可以把它如下拆开来分析,代码如下:

    String str;
    
    //1. 这是用Optional包装了String的可空对象
    Optional<String> strOpt= Optional.ofNullable(getMsgFormDB());  
    
    //2. map函数是将Optional包装的对象转换成其他对象,可以是其他类型对象,这里只是将String转换成不同值String对象,并且map函数是有一个隐含逻辑的,就是只有Optional里面第二次String 不为null时才执行你传入map中的Lambda表达式。
    strOpt= strOpt.map(d->d.trim()); 
    
    //3 ...
    strOpt= strOpt.map(d->d.replace(getMsgFromWebService()))
    //4 ...
    strOpt= strOpt.map(d->d.trim())
    //5 orElseGet函数的意思是,如果strOpt中String对象为null,则执行传入其中的表达式,这一行是返回了一个空字符串。Optional还有一个类似的orElse(),它和orElseGet区别是,它返回一个Optional包装类型对象
    strOpt= strOpt.orElseGet(() -> Strings.EMPTY);
    

    上面的代码和上上面的代码,其整个组成的逻辑就是,用Optional包装从调用getMsgFormDB()方法返回的对象,如果getMsgFormDB()返回的对象不为null,将其转换成一个去除空格的String对象,并一次执行第三不,第四步的转换。 如果getMsgFormDB()返回的对象为null,则不执行2,3,4这几个传入map函数中的表达式,我们且当做未执行2,3,4这三行代码,直接执行了第5行代码。

    以上示例展示了如何使用Optional类来组装我们的代码,它可以使我们的代码变成一个链式的,易于阅读的,且一定曾读增强了代码的健壮性。Optional类还有许多其他函数来做一些我们需要的常规操作,如: isPresent(),isPresent(),isPresent(),ifPresent等等,可参考如下教程: https://www.runoob.com/java/java8-optional-class.html

    另外有一个实践建议,我不是很清楚它是否完全正确,我们可以权衡一下。

    • 我们应该尽量避免在代码中范型型参,方法入参或返回类型类型中使用Optional,如:
    // 可以这样用
    
    public void youMethod(){
    Any str=Optional.ofNullable(getObjectByOthers()).orElseGet(()-> new Any());
    
    //... doSomething
    }
    
    // 不要这样做
    public Optional<Any> youMehtod(Optional<Any> arg){
    
    }
    
  • 相关阅读:
    python 列表 list
    2019书单
    2020书单
    python 字符串
    python 运算符 取余 取商 in not in
    jmeter——安装和运行
    python——CGI编程【 python脚本在Apache上运行前的注意事项】
    python——CGI编程【Apache 支持 python脚本所需要的配置】
    whistle——真机移动端页面调试【在页面注入js实现模拟PC浏览器的Console功能】
    whistle——真机移动端页面调试【查看、修改真机端的页面DOM结构及样式】
  • 原文地址:https://www.cnblogs.com/xuzimian/p/11865454.html
Copyright © 2020-2023  润新知