简体   繁体   English

Java 7构造函数

[英]Java 7 Constructor

I saw that in Java 7 , they introduced the method Objects.requireNonNull(T obj, String message) . 我在Java 7看到,他们引入了方法Objects.requireNonNull(T obj, String message)

Checks that the specified object reference is not null and throws a customized NullPointerException if it is. 检查指定的对象引用是否为null,如果是,则抛出自定义的NullPointerException This method is designed primarily for doing parameter validation in methods and constructors with multiple parameters. 此方法主要用于在具有多个参数的方法和构造函数中进行参数验证。

Before starting to reformat my code, I would ask here to have some feedback about using that. 在开始重新格式化我的代码之前,我会在这里请求一些关于使用它的反馈。

 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");
   }

Is it a better practice to use it directly when I construct my object (I was thinking about if I create a library or other stuff for developers) ? 在构造我的对象时直接使用它是一种更好的做法(我在考虑是否为开发人员创建库或其他东西)?

Or should I leave it as a "classic/old one" constructor ? 或者我应该把它留作“经典/旧的”构造函数?

As you can see, there is disagreement whether an NPE or some other exception should be thrown 1 . 正如您所看到的,对于是否应抛出NPE或其他异常存在分歧1

If you accept that an NPE is more appropriate than the alternatives, AND this is a situation where null is unequivocally incorrect, then: 如果您接受NPE比替代方案更合适,并且这是null明确不正确的情况,那么:

  • it is better to throw the NPE early; 最好早点扔掉NPE; ie in the constructor, and 即在构造函数中,和
  • it is better to throw it with a custom exception message; 最好使用自定义异常消息抛出它; ie not a null as happens when the JVM throws NPEs. 即,当JVM抛出NPE时,不会发生null

In that context using Objects.requireNonNull is clearly good practice. 在那个上下文中使用Objects.requireNonNull显然是很好的做法。


You could also use Java assertions for this, but you'd need to make a judgement as to whether it is a good or bad thing that the test could be turned off. 您也可以使用Java断言,但是您需要判断测试是否可以关闭是好事还是坏事。 You have to consider whether the performance benefit of turning the early check off outweighs the problems that could be caused by not checking earlier. 您必须考虑转换早期检查的性能优势是否超过了之前未检查可能导致的问题。 For instance, suppose you see an NPE in production with assertions turned off ... and you can't diagnose it. 例如,假设您在生产中看到NPE已关闭断言...而您无法对其进行诊断。 Do you turn on assertions? 你打开断言吗? Will the assertions change the behaviour of the code? 断言是否会改变代码的行为? Will it slow your system down (due to lots of other assertion checks)? 是否会降低系统速度(由于许多其他断言检查)? Is the situation that triggered the NPE likely to recur? 引发NPE的情况是否可能再次发生?

(Threading-related bugs are often "once in a blue moon" things that are exceedingly difficult to reproduce. I would argue that you need the information to diagnose the problem ANY time that it occurs ... not just when you've got assertion checking enabled.) (线程相关的错误通常是“曾经在蓝色月亮中”非常难以重现的事情。我认为你需要信息来诊断问题,无论何时发生......不仅仅是当你有断言时检查已启用。)


The backwards compatibility argument is possibly relevant. 向后兼容性参数可能是相关的。 However, as a general rule you don't write your code to run on old Java platforms. 但是,作为一般规则,您不要编写代码以在旧Java平台上运行。 If you have a specific requirement to support old versions of Java ... that's different. 如果您有特定要求支持旧版Java ...那就不同了。 But if that was the case, you shouldn't be doing your development against the Java 7 APIs at all ... so your compiler / IDE should flag the Objects class as compilation error. 但如果是这种情况,你根本不应该对Java 7 API进行开发......所以你的编译器/ IDE应该将Objects类标记为编译错误。

(Restricting yourself to only using the older APIs when you don't need to will make your code quality suffer, and make it "out of date" earlier. The whole point of the new stuff is to make it easier to write reliable / maintainable applications. Deliberately not using it is ... perverse. Imagine if you restricted yourself to Java 1.1 ...) (限制自己只使用旧的API时,你不需要会让你的代码质量受到影响,并使其“过时”早。新的东西全部意义在于使更容易地编写可靠/维护故意不使用它是...反常。想象一下,如果你限制自己使用Java 1.1 ......)


1 - FWIW, I think NPE's are just fine. 1 - FWIW,我认为NPE很好。 And NPE with a message is more specific than (say) IllegalArgumentException , and there's lots of precedents in the Java standard class libraries for constructors, etc that are documented as throwing NPEs. 带有消息的NPE比(例如) IllegalArgumentException更具体,并且Java标准类库中有许多先例用于构造函数等,这些先例被记录为抛出NPE。 Besides, this method was clearly designed to be used this way. 此外,这种方法显然是以这种方式使用的。

I don't feel comfortable with the fact that requireNonNull() throws a NullPointerException . 对于requireNonNull()抛出NullPointerException这一事实我感到不舒服。 In my opinion, throwing the classic IllegalArgumentException makes the intention more clear. 在我看来,抛出经典的IllegalArgumentException使得意图更加明确。 One can use Assertions as well with the advantage that they can be selectively turned on and off. 人们也可以使用Assertions ,其优点是可以有选择地打开和关闭它们。

On the top of it, if you want to expose your code as a library one should usually make an effort to support the oldest JDK possible. 最重要的是,如果要将代码公开为库, 通常应该尽力支持最旧的JDK。

EDIT : I'd like to add that pick any well known framework today and you'll find that their APIs would always throw exceptions with names so descriptive you almost instantly get to know what's wrong. 编辑 :我想补充说今天选择任何一个众所周知的框架,你会发现他们的API总会抛出具有如此描述性的名称的异常,你几乎立刻就会知道什么是错的。

To give an example, what happens when a Spring container finds that a @Required property on a managed bean could not be injected and so has remained NULL . 举一个例子,当一个Spring容器发现托管bean上的@Required属性无法注入并因此保持为NULL You certainly don't get a NullPointerException with as descriptive an error message as possible. 你当然不会得到一个NullPointerException作为描述性的错误消息。

You get a BeanCreationException wrapped around a BeanInitializationException giving further information about the member variable that is still null in a descriptive enough error message like: Property 'center' is required for bean 'circle'. 你会得到一个BeanCreationException包含一个BeanInitializationException提供了有关成员变量的更多信息,该变量在描述性足够的错误消息中仍然为nullBeanInitializationException '需要属性'center'。

If you happen to have setters for bar and baz , you should do it in the setters: 如果你碰巧有barbaz setter,你应该在setter中做:

public Foo(Bar bar, Baz baz) {
    setBar(bar);
    setBaz(baz);
}

public void setBar(Bar bar) {
    this.bar = Objects.requireNonNull(bar, "bar must not be null");
}

public void setBaz(Baz baz) {
    this.baz = Objects.requireNonNull(baz, "baz must not be null");
}

Otherwise the method you showed is fine. 否则你展示的方法很好。

Regarding the question about doing it at all - if your object is completely useless when bar and baz are null, you might as well do the null check at the constructor&setters. 关于完成它的问题 - 如果barbaz为null时你的对象完全没用,你也可以在构造函数和setter中进行null检查。 But if your object can be used when they are null - even if that usage is just checking that they are null and setting them with a setter, assuming that is a legitimate usage of your class - then you can let your users do it. 但是如果你的对象在它们为null时可以被使用 - 即使这个用法只是检查它们是否为空并用setter设置它们,假设这是你的类的合法用法 - 那么你可以让你的用户这样做。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM