Java autoboxing and ternary operator madness

后端 未结 4 805
感动是毒
感动是毒 2020-11-30 07:41

Just spent a frustrating couple of hours debugging this code:

    LinkedHashMap rsrqs = new LinkedHashMap();
           


        
相关标签:
4条回答
  • 2020-11-30 08:08

    Ternary expressions, like any expression, have a type that is determined by the compiler. If the two sides of the ternary expression have what looks like different types, then the compiler will try and find a common base type using the least ambiguous of the two options. In your case, the -1 is least ambiguous, and so the type of the ternary expression is int. Sadly, the compiler doesn't use type inference based on the receiving variable.

    The expression rsrqs.get(boxedPci.toString()) is then evaluated and forced into type int to match the ternary expression, but because it's null it throws the NPE.

    By boxing the -1, the value of the ternary expression is Integer, and so you're null-safe.

    0 讨论(0)
  • 2020-11-30 08:09

    Well, Integer.valueOf(String) returns an Integer and -1 is a primitive int. The first example is forced to unbox because one term is a primitive. You could also have used

    Integer boxedRsrq = boxedPci != null ? 
        rsrqs.get(boxedPci.toString()) : (Integer) -1;
    

    which would have boxed the -1.

    0 讨论(0)
  • 2020-11-30 08:20
    1
    

    is an int, not an Integer. So, Java is going to un-box your Integer to int, which causes the NullPointerException. When you auto-unbox a null Integer, it results in a NullPointerException. ( reference here )

    But when you use

     Integer.valueOf(-1) 
    

    it doesn't need to auto-unbox it, which leads to no exceptions.

    0 讨论(0)
  • 2020-11-30 08:25

    The explanation can be concluded from the information in java language specification: 15.25. Conditional Operator ? :.

    From the table there, you get the information, that, if the second operand (rsrqs.get(boxedPci.toString())) is of type Integer and the third operand is of type int, the result will be of type int.

    That however means, that

    Integer boxedRsrq = boxedPci != null ? rsrqs.get(boxedPci.toString()) : -1;
    

    is semantically the same as

    Integer boxedRsrq = boxedPci != null ? ((int)rsrqs.get(boxedPci.toString())) : -1;
    

    But that means you get a NullPointerException, if you get null from the map, which obviously happens.

    If you cast the third operand to Integer, the second operand will never be cast to int and no NPE happens.

    0 讨论(0)
提交回复
热议问题