各种各样的坑之-optional和==

    作为程序员没有遇到坑那是不太可能的,这篇文章记录我遇到的一些坑,避免以后再次遇到。

    1、比较两个Integer类型的值是否相等使用“==”

        缘起:一条lambda表达式引起的BUG,  这条表达式是从List里找出对应ID的记录。    

UserAccountInfo userInfo = list.Stream().filter(r->r.getId()==userId).findFirst().orElse(null);

        单元测试时,是ok的(单元测试时userId=4)。上了测试环境甚至上到生产环境才发现这是一个大BUG.  我们来分析一下 “==”, 这是比较的内存地址, 两个值相同的Integer内存地址不一定相同。

        看以下例子:            

    public static void main(String[] args) {
        //1
        Integer a= 100, b=100;
        System.out.println(a==b); //true
        //2
        a=100;
        b=new Integer(100);
        System.out.println(a==b);  //false
        //3
        a=200;
        b=200;
        System.out.println(a==b); //false
    }

        这是享元模式在作怪,不知道的可以看看Integer的源码,这里不做详细介绍。

        那么我们在程序里如何比较两个Integer值是否相等呢? 有以下几种方法

            

        System.out.println(a.intValue()==b);
        
        System.out.println(a.compareTo(b)==0);
        
        System.out.println(a.equals(b));

        采用第一种方法的一看就知道刻意为了避规享元模式造成的影响, 将包装类型的值换成基本类型来比较,但是这样的代码看起来有点low, 或者说有点作(好像刻意让人知道你懂享元模式似的,这本身不是啥高深的东西,有啥好炫耀的)。

        第二种方法是直接比较值,第三种方法利用Object的equals方法,当然也是比较值,  我个人推荐第二种方式来比较,因为从可读性来说是比较可取的。

        结论:比较两个Integer类型是否相等时建议使用 compareTo 方法。  这条规则对Short、 Long类型同样适用。

  

    2、Optional的get()、orElseGet()方法

        高手请略过, 出现这种问题的一般会是刚使用Optional又没有看过Optional源码或者读过相关文档的朋友,我也是其中之一。

        缘起:参考第一条的lambda表达式 

    UserAccountInfo userInfo = list.Stream().filter(r->r.getId()==userId).findFirst().get();

      "=="的问题还未解决的时候, r.getId()==userId 会返回false,所以导致根据userId查不到数据, 报 NosuchElementException。

            我们又修改了代码                     

      Optional<UserAccountInfo> userInfo = list.Stream().filter(r->r.getId()==userId).findFirst();
      if(userInfo==null) return null;
      return userInfo.get();

            还是报NosuchElementException,查看Optional的源代码才发现,lambda表达式返回的Optional是不会为空,所以和没修改前是一样的,都会执行get()方法。

            继续看源代码, 发现有个orElseGet()、还有个orElse()方法,  orElseGet()方法会调用传入参数的get()方法,所以参数不能传null,否则会报空指针。 orElse();方法会直接返回传入的值。 源码如下 

    /**
     * Return the value if present, otherwise return {@code other}.
     *
     * @param other the value to be returned if there is no value present, may
     * be null
     * @return the value, if present, otherwise {@code other}
     */
    public T orElse(T other) {
        return value != null ? value : other;
    }

    /**
     * Return the value if present, otherwise invoke {@code other} and return
     * the result of that invocation.
     *
     * @param other a {@code Supplier} whose result is returned if no value
     * is present
     * @return the value if present otherwise the result of {@code other.get()}
     * @throws NullPointerException if value is not present and {@code other} is
     * null
     */
    public T orElseGet(Supplier<? extends T> other) {
        return value != null ? value : other.get();
    }
        最终我们改成 

    UserAccountInfo userInfo = list.Stream().filter(r->r.getId().compareTo(userId)).findFirst().orElse(null);
        “==”和Optional的问题都得到圆满解决。


                


猜你喜欢

转载自blog.csdn.net/xmc125/article/details/80389526