踩了一个java中三目运算符的坑

        前两天在开发中遇到了一个很诡异的NPE情况,最后发现是三目运算符的编译问题,这里记录一下。

        简化后的代码如下:

Map<String, Long> map = Maps.newHashMap();
map.put("a", 123L);
TmpCls cls = new TmpCls();
cls.setPrice(ObjectUtils.isEmpty(map) ? 0L : map.get("b"));

        原代码的map其实是从数据库查出的结果,如果没查到数据,price就是0,否则就取查到的数据,有时就会出现上面例子的情况,map.get()取不到数据。

        从代码本身来看,是没任何问题的,但是遇到这种取不到的情况,就会报一个NPE,百思不得其解。最后看了一下反编译的结果,才发现其中原因。

        反编译以后,最后的那个三目运算符的代码是这样的

cls.setPrice(ObjectUtils.isEmpty((Object)map) ? 0L : ((long)map.get("b"));

        会发现,它会将map.get()方法外包进行了long型强转,如果这里没有获取到信息,那么就是null了。

        具体原因还真不清楚,大概猜想,应该是编译器根据目标类型进行了推导的结果。

        解决的办法有三种:

        1、不使用三目运算符,这个比较简单,就不说明了

        2、对原数据进行判空操作,可以使用Optional进行简单包装。

cls.setPrice(ObjectUtils.isEmpty(map) ? 0L : Optional.ofNullable(map.get("b")).orElse(0L));

        3、将后面的逻辑移到外面先做处理,不过这里也有一个小问题。

long l=ObjectUtils.isEmpty(map) ? 0L : map.get("b");//NPE
Long l=ObjectUtils.isEmpty(map) ? 0L : map.get("b");//正常

        我也是通过这个测试,才推断应该是编译器进行了类型推导的。

        另外还需要说一下,我用eclipse和idea都进行了这个测试,发现在eclipse中,第三种解决办法里,即使使用包装类型,也依然会有NPE产生,这个应该是IDE的问题吧,因为我查了一下用的都是自己安装的JDK8。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章