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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2382058/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 06:48:09  来源:igfitidea点击:

Unboxing Null-Object to primitive type results in NullPointerException, fine?

javanullpointerexception

提问by Christopher Klewes

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

这个片段抛出一个,NullPointerException因为它被拆箱为原始类型并被Long.longValue()调用,对吗?

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

如果您有这样的代码段,那就更容易看出来了:

long value = (Long) null;

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

NullPointerException在这样更复杂的情况下更难进入:

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 IllegalArgumentExceptionwith a message like "You're trying to cast a null-Object into a primitive type, this can't be done!"

那么 Java 编译器是否有可能从中制作出更舒适的 Exception 呢?我更喜欢IllegalArgumentException带有类似“您正在尝试将空对象转换为原始类型,这是不可能的!”的消息。

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.

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

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

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

采纳答案by Michael Borgwardt

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 NullPointerExceptionis the natural result of unboxing a null(and in fact mandated by the JLS).

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

Throwing a different exception would require checking for nulltwiceduring 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.

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

回答by Pops

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

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

Certainly at runtime, when the exception is thrown, the compiler knows that the problem is a nullvalue. 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 possibleto create a compiler that will include that in the error description. But if you want a special message for nullvalues, 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.

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

回答by eckes

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.

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

回答by oluies

Since Java 8 SE there is also Optional.ofNullable

由于 Java 8 SE 也有 Optional.ofNullable

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