53

这个片段抛出一个NullPointerException由于它被取消装箱为原始类型并被Long.longValue()调用的事实,对吧?

如果您有这样的片段,那甚至很容易看到:

long value = (Long) null;

但是NullPointerException在这样的更复杂的情况下更难:

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

那么Java-Compiler是否有可能从中产生更舒适的异常?我更喜欢这样IllegalArgumentException的消息,例如“您正在尝试将 null-Object 转换为原始类型,这无法完成!”

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

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

4

4 回答 4

94

根据Java 语言规范,拆箱是通过调用Number.longValue(),Number.intValue()等进行的。没有发生特殊的字节码魔术,与手动调用这些方法完全相同。因此,这NullPointerException是拆箱 a 的自然结果null(实际上是 JLS 规定的)。

抛出不同的异常需要在每次拆箱转换期间检查null 两次(一次确定是否抛出特殊异常,一次在实际调用方法时隐式检查)。我想语言设计者认为它没有足够的用处来保证这一点。

于 2010-03-04T19:37:42.920 回答
24

由于 Java 8 SE 还有 Optional.ofNullable

long value = Optional.ofNullable(obj.getProperty(propertyModel.getName())).orElse(0L)));
于 2017-11-23T20:40:40.557 回答
1

这不是什么IllegalArgumentException意思。编译器不保证该值将null持续到运行时。它所知道的只是类型,在您的示例中可能是String.

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

于 2010-03-04T19:33:24.707 回答
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 和异常层次结构或相关应用程序的日志记录约定。很难做到通用。

于 2013-10-15T21:51:37.083 回答