Community
Participate
Working Groups
Consider the following expression: HashMap<String,Integer> m = new HashMap<String,Integer>(); Integer w = (cond ? 1 : m.get("test")); If cond is true, this gets evaluated as: Integer w = new Integer(1); If cond is false, this gets evaluated as: Integer w = new Integer(m.get("test").intValue()); This throws a NullPointerException. What would be most intuitive (and more efficient) is if the false case did not go through the (redundant) autounbox/autobox step, so it evaluated as: Integer w = m.get("test"); That would allow the value w to be tested for null after the (?:) step were complete, however this is disallowed by JLS3 15.25, as confirmed in Bug 95868 by Philippe Mulet, because since both clauses of the (?:) expr can be treated as int, the autounboxing must occur. Therefore I propose that the user be warned in this situation (where an execution branch must be autounboxed, but is then re-autoboxed as part of the same expression) that a NullPointerException may be thrown, and this may not be what the user expects. The user could then rewrite the expression as Integer w; if (cond) w = 1; else w = m.get("test"); Which does not exhibit the problem. (For the record, I think JLS3 15.25 is somewhat analogous to the situation where subclauses of a (?:) expression share a supertype, but must be manually casted to the supertype to avoid a warning or error about incompatible types.) The deeper problem is not with the (?:) expression, but consists of at least the following: (1) It may be difficult or impossible to determine if a given subexpression could potentially return a null expression, especially if a function call is involved. I believe this is actually uncomputable (like the stopping problem) in the general case. (2) The problem I describe can also result due to interactions between autounboxing/autoboxing operations in different expressions, or even different statements. In the worst case, this is again generally uncomputable if these statements are in nonoverlapping scopes (and say depend upon a class field). Problem (1) could be solved automatically in simple cases, such as (?:). Probably you could then extend the Java Collections Framework using annotations in all other cases, adding an annotation like "@CanReturnNull", to hint to the IDE that it needs to do null autounbox analysis and possibly report a warning. (That actually creates problem (3): detecting execution branches where the user actually checks if the return value is null, and then supressing further warnings on those execution branches. This is a little easier than the other two though.) Problem (2) is similar to uninitialized variable detection. There's an obvious practical limit to how far you would take this analysis (Java appears to track all possible execution flows within a method, but not between methods, which is entirely reasonable).
Thanks. Will revisit post 3.1.
To be investigated for 3.2 M4
There are two parts to this: a) relate m.get() upon a newly created map to null; b) given an Integer i that may be null, warn on the conditional expression because of the somewhat hidden back and forth boxing conversion. As far as today, none of these is supported by bug 110030. Some of the boxing/unboxing issues are supported though (see NullReferenceTest#test0040 through test0044).
Since inter-procedural analysis is not in 3.2 scope, this should be deferred.
As of now 'LATER' and 'REMIND' resolutions are no longer supported. Please reopen this bug if it is still valid for you.