Java 7 构造函数

2022-09-01 23:39:43

我看到,在 中,他们引入了方法 Objects.requireNonNull(T obj, String message)。Java 7

检查指定的对象引用是否不为 null,并抛出一个自定义值(如果它是)。此方法主要用于在具有多个参数的方法和构造函数中执行参数验证。NullPointerException

在开始重新格式化我的代码之前,我会在这里要求一些关于使用它的反馈。

 public Foo(Bar bar, Baz baz) {
         /** Old one
         this.bar = bar;
         this.baz = baz;
         **/
         this.bar = Objects.requireNonNull(bar, "bar must not be null");
         this.baz = Objects.requireNonNull(baz, "baz must not be null");
   }

当我构造对象时直接使用它是否是一个更好的做法(我正在考虑是否为开发人员创建库或其他东西)?

或者我应该把它保留为“经典/旧”构造函数?


答案 1

如您所见,对于是否应引发 NPE 或其他异常存在分歧1

如果您接受NPE比替代方案更合适,并且这种情况显然是不正确的,那么:null

  • 最好尽早抛出NPE;即在构造函数中,以及
  • 最好用自定义异常消息抛出它;也就是说,当JVM抛出NPE时不会发生这种情况。null

在这种情况下,使用显然是很好的做法。Objects.requireNonNull


你也可以使用Java断言,但是你需要判断是否可以关闭测试是好事还是坏事。您必须考虑关闭提前检查的性能优势是否超过因未提前检查而可能导致的问题。例如,假设您在生产中看到一个 NPE,其中断言已关闭...你无法诊断它。是否打开断言?断言会改变代码的行为吗?它会减慢系统速度(由于许多其他断言检查)吗?触发 NPE 的情况是否可能再次发生?

(与线程相关的错误通常是“曾经在蓝月亮中”的东西,非常难以重现。我认为您需要这些信息来诊断问题,无论何时发生...而不仅仅是当您启用了断言检查时。


向后兼容性参数可能相关。但是,作为一般规则,您不会编写代码以在旧的Java平台上运行。如果您有支持旧版Java的特定要求...那就不一样了。但是,如果是这样的话,你根本不应该针对Java 7 API进行开发......所以你的编译器/IDE应该将类标记为编译错误。Objects

(将自己限制为仅在不需要时使用较旧的API,这将使您的代码质量受到影响,并使其更早“过时”。新东西的全部意义在于使编写可靠/可维护的应用程序变得更加容易。故意不使用它是...反常。想象一下,如果你把自己限制在Java 1.1...


1 - FWIW,我认为NPE很好。带有消息的 NPE 比 IllegalArgumentException 更具体,在 Java 标准类库中有很多用于构造函数等的先例,这些先例被记录为抛出 NPE。此外,这种方法显然是为以这种方式使用而设计的。


答案 2

我对抛出一个事实感到不舒服。在我看来,抛出经典会让意图更加清晰。人们也可以使用它们的优势,即它们可以有选择地打开和关闭。requireNonNull()NullPointerExceptionIllegalArgumentExceptionAssertions

最重要的是,如果你想将代码公开为一个库,通常应该努力支持最旧的JDK。

编辑:我想添加一下今天选择任何众所周知的框架,你会发现他们的API总是会抛出带有描述性名称的异常,你几乎可以立即知道出了什么问题。

举个例子,当Spring容器发现管理豆上的属性无法注入并且因此仍然存在时会发生什么。您当然不会收到尽可能具有描述性的错误消息。@RequiredNULLNullPointerException

你会得到一个关于成员变量的进一步信息,它仍然在描述性的足够错误消息中,例如:属性“中心”是bean“circle”所必需的。BeanCreationExceptionBeanInitializationExceptionnull