这个片段会抛出一个
NullPointerException
,因为它被拆箱为原始类型并且 Long.longValue()
被调用,对吧?
如果您有这样的片段,那就更容易看出:
long value = (Long) null;
但是
NullPointerException
在这样更复杂的情况下就更难了:
long propertyValue = (Long) obj.getProperty(propertyModel.getName());
那么 Java 编译器是否有可能从中产生更舒适的异常?我更喜欢带有类似消息的
IllegalArgumentException
“您正在尝试将 null 对象转换为原始类型,这是无法完成的!”
这样不是更合适吗?你怎么认为?这在运行时是否可能?我们能确定这个演员阵容吗?我还没看过java字节码。也许它可以用于解决方案。
这个问题可以回答:我想知道是否有可能实现这种行为!
根据 Java 语言规范,拆箱是通过调用
Number.longValue()
、Number.intValue()
等进行的。没有发生特殊的字节码魔法,与手动调用这些方法完全相同。因此,NullPointerException
是拆箱 null
的自然结果(实际上是 JLS 强制要求的)。
抛出不同的异常需要在每次拆箱转换期间检查
null
两次(一次确定是否抛出特殊异常,一次在实际调用方法时隐式检查)。我想语言设计者认为它没有足够的用处来保证这一点。
从 Java 8 SE 开始,还有Optional.ofNullable
long value = Optional.ofNullable(obj.getProperty(propertyModel.getName())).orElse(0L);
这不是
IllegalArgumentException
的意思。编译器无法保证该值在运行时之前都是 null
。它只知道类型,在您的示例中可能是 String
。
当然在运行时,当抛出异常时,编译器知道问题出在
null
值上。如果您使用调试器,您可以自己看到这一点。因此,从技术角度来看 - 这是对您问题的简短回答 - 是的,有可能创建一个编译器,将其包含在错误描述中。但如果您想要 null
值的特殊消息,接下来该怎么办?针对超出某个可接受范围超过 10 的整数的特殊消息?诚然,这是一个愚蠢的例子,但我希望它能说明问题。
针对此类情况编写一个小型私人助手是个好主意。这些可以处理生成正确的转换、错误消息和默认值。
最好将足够的操作“状态”放入异常中(在本例中是选项名称和值 - 如果未找到,甚至可能是选项映射的字符串表示形式)。
类似:
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 和异常层次结构或相关应用程序的日志约定。很难使其通用。