Community
Participate
Working Groups
I get a NullPointerException running the following code when yKey does not exist as a key in the HashMap y: HashMap<String,Integer> y = getHashMap(); Integer w = (x.equals("X") ? 0 : y.get(yKey)); What appears to be happening is this is interpreted as: Integer w = new Integer(x.equals("X") ? 0 : (int) y.get(yKey)); rather than Integer w = (x.equals("X") ? new Integer(0) : y.get(yKey)); which is probably what should happen. (Unless it is defined otherwise in the autoboxing/unboxing spec?) That way I can test if (w == null) after this assignment. The current behavior caused a hard-to-trace bug, and is not very intuitive. Thanks!
I presume you saw it in M7?
Yes, I believe it was 3.1M7, although it could have been 3.1M6 (I'm at home right now so I can't check). Let me know if you need the version number for sure. One thing I should additionally mention is that the former case always performs an unbox followed by an autoboxing, whereas the latter case performs just an autoboxing, and only if the condition is true (otherwise it does no unboxing/autoboxing). So the current behavior is actually less efficient than the ideal, as well as the problem I mentioned where a null pointers exception is thrown when it doesn't need to be.
Actually, sorry that is not quite correct -- the "former case" (the current behavior) is to perform an unboxing only if the condition is false, although it always has to do the autoboxing step. So it's still less efficient than it could be, but it may not be quite as bad efficiency-wise as I described, depending on how often the condition is true. I don't have any easy way to test this on Sun's compiler right now -- how does Sun compile this expression?
Javac agrees with us, and http://java.sun.com/j2se/1.5.0/docs/guide/language/autoboxing.html mentions this scenario as legite: "[...]. The result of all this magic is that you can largely ignore the distinction between int and Integer, with a few caveats. An Integer expression can have a null value. If your program tries to autounbox null, it will throw a NullPointerException. [...]" Added AutoboxingTest#test104
Now auto-unboxing here remains questionnable, feels like the conditional operator should be smarter at noticing some of its operand need nothing.
JLS3 15.25 expects this behavior. Both operands are convertible to primitive type 'int', thus the type of operation is 'int'. Then it needs boxing to match assigned variable type 'Integer'.
Closing since working as spec'ed
Salut Phillipe, Thanks for doing the work to figure out what the correct behaviour is supposed to be. Is it possible that Eclipse could just report a warning here? It is entirely possible to avoid the implicit NullPointerException if the code is reworked as an if statement rather than as a (?:) statement. That seems very counter-intuitive to me, and it took me a while to figure out why I was getting an exception there. So the following code will never throw an exception: Integer w; if (x.equals("X")) w = 0; else w = y.get(yKey); Up until now I have never seen a case where (?:) and an if statement like the above do not behave identically. (The only difference, before autoboxing/unboxing, is that an if statement like that would implicitly take care of polymorphism without a cast, and (?:) may not do so -- perhaps this corresponds to the behaviour in JLS3 15.25?) It is also possible that while the current behavior is correct according to JLS3 15.25, that some earlier Java standard about the exact semantics of (?:) is actually being violated. Whether or not it is, this certainly goes counter to intuition. So is an Eclipse warning in order, just so the NullPointerException could be avoided if the programmer is notified? I have a gut feeling too that other situations like this could arise too where an exception could be avoided, or at least where it's easy to detect that the user is doing something where they may not realize that an exception could be thrown. I forsee autoboxing/autounboxing becoming so "accepted" that nobody ever thinks about what's going on "under the hood", and this could give rise to a whole new class of software bugs where exceptions are thrown that should have been caught but are not.
We provide warnings for boxing/unboxing operation. In order to detect this special scenario, I am guessing this should be bundled with null reference analysis which we'd like to consider in the future. Would you mind opening a separate defect about this ? So we can look at it in the future ?
Created bug 96063 as requested. Je vous remercie.