Java 三目运算符(conditional operator?:)

参考

  • 伯乐在线 - 你真的会用 Java 中的三目运算符吗?
  • 三目运算符的官方文档
  • Java_Chuck - JAVA笔记-三目运算符返回值规则

问题

下面这段代码竟然报了NullPointerException异常.

public static void main(String[] args) {
      Map map = new HashMap<>();
       // Exception in thread "main" java.lang.NullPointerException
       boolean b = (map!=null ? map.get("test") : false);
   }

问题来源是Java的Autoboxing和Boxing机制.

三目运算符求值顺序

首先是右结合的.

The conditional operator is syntactically right-associative (it groups right-to-left). Thus, a?b:c?d:e?f:g means the same as a?b:(c?d:(e?f:g)).

其次再关注整体的返回值类型是什么, 首先 ? Expression1 : Expression2中的两个表达式, 要么是同一个类型, 要么是能够相互转换的, 但是最后会统一为一个类型, 规则(下面只摘录了一部分, 完整的可以去三目运算符的官方文档查看)如下:

  1. If the second and third operands have the same type (which may be the null type), then that is the type of the conditional expression.

  2. If one of the second and third operands is of primitive type T, and the type of the other is the result of applying boxing conversion (§5.1.7) to T, then the type of the conditional expression is T.

  3. If one of the second and third operands is of the null type and the type of the other is a reference type, then the type of the conditional expression is that reference type.

对于上面的boolean b = (map!=null ? map.get("test") : false);:

  • map.get("test") 的返回值是Boolean
  • false 是原始类型boolean

根据规则2, boolean是原始类型, 而Boolean类型是boolean装箱后的结果, 即Boolean. 所以最终的返回值类型为boolean.
然后开始对整体求值, 首先map != null肯定是成立的, 所以会对map.get("test")求值, 因为map中不存在test这个key, 所以get方法返回了null, 这也是整体的返回值. 因为map.get()返回值类型是Boolean, 而因为规则2, 所以会将map.get()对的返回值进行拆箱操作, 即调用Boolean.booleanValue()方法, 而此时map.get()的返回值是一个null, 所以出现了NullPointerException.

经过进一步测试, 有以下结果:
根据B那句赋值语句来看, 应该是编译器判断又要从boolean转换回Boolean所以map.get()的结果应该不会再拆箱了.

        Map map = new HashMap<>();
        // Exception in thread "main" java.lang.NullPointerException
//        boolean b = (map!=null ? map.get("test") : false);

        // 没有异常
//        Boolean B = (map!=null ? map.get("test") : false);

        // Exception in thread "main" java.lang.NullPointerException
//        if ((map!=null ? map.get("test") : false)){
//            ;
//        }

        // Exception in thread "main" java.lang.NullPointerException
//        boolean b1 = (map!=null ? map.get("test") : Boolean.FALSE);

你可能感兴趣的:(Java 三目运算符(conditional operator?:))