代码之家  ›  专栏  ›  技术社区  ›  Christopher Klewes

将空对象取消绑定到基元类型会导致NullPointerException,可以吗?

  •  35
  • Christopher Klewes  · 技术社区  · 14 年前

    此代码段引发 NullPointerException 因为它未与原始类型绑定, Long.longValue() 是叫的,对吗?

    如果你有这样一个片段,你甚至很容易看到:

    long value = (Long) null;
    

    但是 空指针异常 在这样复杂的情况下更难做到:

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

    那么,Java编译器不可能有一个更舒服的例外吗?我想要个 IllegalArgumentException 带着这样的信息 “您试图将空对象强制转换为基元类型,但这无法完成!”

    这不更合适吗?你怎么认为?这在运行时也是可能的吗?我们能确定这个演员表吗?我还没有看过Java字节码。也许可以用在溶液中。

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

    4 回复  |  直到 6 年前
        1
  •  66
  •   jiahao    11 年前

    根据 Java language specification ,通过调用取消装箱 Number.longValue() , Number.intValue() 等等。没有特殊的字节码魔术发生,就像你手动调用那些方法一样。因此, NullPointerException 是拆箱的自然结果 null (实际上是由JLS授权的)。

    引发不同的异常需要检查 无效的 两次 在每次取消装箱转换期间(一次确定是否引发特殊异常,一次隐式调用方法时)。我想语言设计者认为它不足以保证这一点。

        2
  •  6
  •   oluies    7 年前

    由于Java 8 SE也有可选的。

    long value = Optional.ofNullable(obj.getProperty(propertyModel.getName())).orElse(0L)));
    
        3
  •  1
  •   Pops Atula    14 年前

    那不是什么 IllegalArgumentException 手段。编译器不能保证该值 null 直到运行时。它只知道类型,在您的示例中可能是 String .

    当然,在运行时,当抛出异常时,编译器知道问题是 无效的 价值。如果您使用的是调试器,则可以自己看到这一点。所以从技术的角度来看——这里是你问题的简短答案-- 是的,有可能 创建一个包含在错误描述中的编译器。但是如果你想要一个特别的信息 无效的 价值观,接下来是什么?超出某些可接受的10个以上的整数的特殊消息?诚然,这是一个愚蠢的例子,但我希望它能说明问题。

        4
  •  1
  •   eckes    11 年前

    为这样的情况写一个小的私人助手是个好主意。它们可以处理生成正确的强制转换、错误消息和默认值。

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

    类似:

    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和异常层次结构,或者应用程序的日志记录约定。很难让它成为通用的。