60

This snippet throws an NullPointerException due to the fact that its unboxed to a primitive type and Long.longValue() is called, right?

Thats even easy to see if you have a snippet like this:

long value = (Long) null;

But the NullPointerException is even harder to get in a more complex situation like this:

long propertyValue = (Long) obj.getProperty(propertyModel.getName());

So isn't there any possibility for the Java-Compiler to make a more comfortable Exception out of this? I would prefer an IllegalArgumentException with a message like "You're trying to cast a null-Object into a primitive type, this can't be done!"

Wouldn't this be more appropriate? What do you think? Is this even possible at runtime? Are we able to determine this cast? I haven't yet looked at the java bytecode. Maybe it could be used in a solution.

This question can be answered: I'd like to know if it's possible to achieve this behaviour!

Ivan Zelenskyy
  • 659
  • 9
  • 26
Christopher Klewes
  • 11,181
  • 18
  • 74
  • 102

4 Answers4

102

According to the Java language specification, unboxing happens via calling Number.longValue(), Number.intValue(), etc. There is no special byte code magic happening, it's exactly the same as if you call those methods manually. Thus, the NullPointerException is the natural result of unboxing a null (and in fact mandated by the JLS).

Throwing a different exception would require checking for null twice during every unboxing conversion (once to determine whether to throw the special exception, and once implicitly when the method is actually called). I suppose the language designers didn't think it useful enough to warrant that.

jiahao
  • 3,373
  • 2
  • 35
  • 36
Michael Borgwardt
  • 342,105
  • 78
  • 482
  • 720
  • 8
    a big plus for explaining WHY it happens - a method like longValue() or doubleValue() is called on a null object. A lot of answers in similar threads end up saying "because unboxing throws NullPointerException" – kiedysktos Feb 01 '17 at 09:52
25

Since Java 8 SE there is also Optional.ofNullable

long value = Optional.ofNullable(obj.getProperty(propertyModel.getName())).orElse(0L)));
oluies
  • 17,694
  • 14
  • 74
  • 117
1

It is a good idea to write a small private helper for cases like this. Those can handle producing correct casts, error messages and default values.

It is good to put enough "state" of the operation into the exception (in this case the option name and the value - maybe even a string representation of the options map if not found).

Something like:

private long safeGetLong(Map<String, Option> options, String name) {
  if (name == null || options == null)
    throw new IllegalArgumentExcption("You need to give options and name. (name="+name+", opts=" + options));
  Object val = options.get(name);
  if (val == null)
    throw new ConfigurationException("The option name="+name+" is unknown");
  if (val instanceof Long)
    return val.longValue();

  String strVal = null;
  try
  {
    strVal = val.toString();
    return Long.parseValue(strVal);
  } catch (Exception ex) {
    throw new ConfigurationException("Cannot parse " + name + "=" + strVal + " into a Long.");
  }
}

Of course having a configuration object which allows typed access is even better.

There are some validation frameworks which could do that for you, but I typically end up writing the code myself as it better fits into IN8L and exception hieracies or logging conventions of the application in question. It is hard to make that generic.

eckes
  • 10,103
  • 1
  • 59
  • 71
1

That's not what IllegalArgumentException means. The compiler has no guarantee that the value will be null until runtime. All it knows is the type, which in your example is likely to be String.

Certainly at runtime, when the exception is thrown, the compiler knows that the problem is a null value. You can see this yourself if you're using a debugger. So from a technology standpoint -- and here is the short answer to your question -- yes, it would be possible to create a compiler that will include that in the error description. But if you want a special message for null values, what's next? Special messages for integers that are outside some acceptable bound by more than 10? Admittedly that's kind of a silly example, but I hope it's illustrative.

Pops
  • 30,199
  • 37
  • 136
  • 151
  • The return type in my example is Object, would it be String i could use Long.valueOf(). Its not forced to be an IllegalArgumentException. I would like a special Exception because there is done some magic for people don't knowing the boxing/unboxing. But okay, its your opinion :) – Christopher Klewes Mar 04 '10 at 19:38
  • I don't understand what you mean about forcing and magic, but if you have a more specific problem, please post additional sample code. Information like the types of variables would be especially useful. – Pops Mar 04 '10 at 19:43