将Null-Object拆箱到原始类型导致NullPointerException,好吗?

时间:2010-03-04 19:19:30

标签: java nullpointerexception

这段代码会抛出一个NullPointerException,因为它已被取消装入原始类型并调用Long.longValue(),对吗?

如果你有这样的代码片段,那就很容易看出来了:

long value = (Long) null;

NullPointerException更难以处理更复杂的情况:

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

因此Java-Compiler是否有可能使Exception更加舒适呢?我希望IllegalArgumentException有一条消息,比如“你试图将一个null-Object转换成一个原始类型,这是不可能完成的!”

这不是更合适吗?你怎么看?这甚至可以在运行时?我们能够确定这个演员吗?我还没有看过java字节码。也许它可以用在一个解决方案中。

可以回答这个问题:我想知道是否有可能实现这种行为!

4 个答案:

答案 0 :(得分:69)

根据Java language specification,取消装箱通过调用Number.longValue()Number.intValue()等进行。没有特殊字节代码魔术发生,它与手动调用这些方法完全相同。因此,NullPointerException是取消装箱null(实际上是由JLS强制要求)的自然结果。

抛出一个不同的异常需要在每次拆箱转换期间检查null 两次(一次确定是否抛出特殊异常,并且在实际调用该方法时隐式执行)。我认为语言设计师并不认为它有用得足以保证。

答案 1 :(得分:9)

自Java 8 SE以来,还有Optional.ofNullable

long value = Optional.ofNullable(obj.getProperty(propertyModel.getName())).orElse(0L)));

答案 2 :(得分:1)

这不是IllegalArgumentException的含义。在运行时,编译器无法保证该值为null。它只知道类型,在你的例子中可能是String

当然,在运行时,抛出异常时,编译器知道问题是null值。如果您使用的是调试器,则可以自己查看。因此,从技术的角度来看 - 这是对您的问题的简短回答 - 是的,有可能创建一个将在错误描述中包含该编译器的编译器。但是,如果您想要null值的特殊消息,那么下一步是什么?对于超出10个可接受范围的整数的特殊消息?不可否认,这是一个愚蠢的例子,但我希望它是说明性的。

答案 3 :(得分:1)

为这样的案例编写一个小型私人助手是个好主意。那些可以处理生成正确的强制转换,错误消息和默认值。

最好将操作的足够“状态”放入异常中(在这种情况下,选项名称和值 - 如果找不到,可能甚至是选项映射的字符串表示)。

类似的东西:

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.");
  }
}

当然,拥有允许键入访问的配置对象会更好。

有一些验证框架可以为您做到这一点,但我通常最终自己编写代码,因为它更适合IN8L和异常的hieracies或相关应用程序的日志记录约定。这种通用很难做到。