Java构造函数风格:检查参数不为空
如果您有一个类接受某些参数但其中任何参数都不允许为 null
,那么最佳实践是什么?
下面的内容很明显,但异常有点不具体:
public class SomeClass
{
public SomeClass(Object one, Object two)
{
if (one == null || two == null)
{
throw new IllegalArgumentException("Parameters can't be null");
}
//...
}
}
这里的异常让你知道哪个参数为空,但构造函数现在非常丑陋:
public class SomeClass
{
public SomeClass(Object one, Object two)
{
if (one == null)
{
throw new IllegalArgumentException("one can't be null");
}
if (two == null)
{
throw new IllegalArgumentException("two can't be null");
}
//...
}
这里的构造函数更整洁,但现在构造函数代码实际上并不在构造函数中:
public class SomeClass
{
public SomeClass(Object one, Object two)
{
setOne(one);
setTwo(two);
}
public void setOne(Object one)
{
if (one == null)
{
throw new IllegalArgumentException("one can't be null");
}
//...
}
public void setTwo(Object two)
{
if (two == null)
{
throw new IllegalArgumentException("two can't be null");
}
//...
}
}
这些风格中哪一个最好?
还是有更广泛接受的替代方案?
What are the best practices if you have a class which accepts some parameters but none of them are allowed to be null
?
The following is obvious but the exception is a little unspecific:
public class SomeClass
{
public SomeClass(Object one, Object two)
{
if (one == null || two == null)
{
throw new IllegalArgumentException("Parameters can't be null");
}
//...
}
}
Here the exceptions let you know which parameter is null, but the constructor is now pretty ugly:
public class SomeClass
{
public SomeClass(Object one, Object two)
{
if (one == null)
{
throw new IllegalArgumentException("one can't be null");
}
if (two == null)
{
throw new IllegalArgumentException("two can't be null");
}
//...
}
Here the constructor is neater, but now the constructor code isn't really in the constructor:
public class SomeClass
{
public SomeClass(Object one, Object two)
{
setOne(one);
setTwo(two);
}
public void setOne(Object one)
{
if (one == null)
{
throw new IllegalArgumentException("one can't be null");
}
//...
}
public void setTwo(Object two)
{
if (two == null)
{
throw new IllegalArgumentException("two can't be null");
}
//...
}
}
Which of these styles is best?
Or is there an alternative which is more widely accepted?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
第二个或第三个。
因为它告诉 API 的用户到底出了什么问题。
为了减少冗长,请使用 commons-lang 中的
Validate.notNull(obj, message)
。因此,您的构造函数将如下所示:将检查放在 setter 中也是可以接受的,具有相同的详细注释。如果您的 setter 还具有保持对象一致性的作用,您也可以选择第三个。
The second or the third.
Because it tells the user of your API what exactly went wrong.
For less verbosity use
Validate.notNull(obj, message)
from commons-lang. Thus your constructor will look like:Placing the check in the setter is also acceptable, with the same verbosity comment. If your setters also have the role of preserving object consistency, you can choose the third as well.
Java 7 将
java.util.Objects.requireNonNull()
添加到每个人都可以使用的 API 中。因此,检查所有参数是否为 null 可以归结为一个简短的列表,例如:旁注:
Java 7 added
java.util.Objects.requireNonNull()
to the APIs everybody can use. So checking all arguments for null boils down to a short list like:Side notes:
您可以使用旨在促进前提条件检查的众多库之一。 Google Guava 中的许多代码都使用
com.google.common.base.Preconditions
结构它有
checkNotNull
即 在 Guava 中广泛使用。然后你可以这样写:大多数方法都被重载,要么不接受错误消息,要么接受固定的错误消息,要么接受带有可变参数的模板化错误消息。
On
IllegalArgumentException
与NullPointerException
虽然原始代码在
null
参数上抛出IllegalArgumentException
,但 Guava 的Preconditions.checkNotNull< /code> 会抛出
NullPointerException
。以下是《Effective Java 第二版:第 60 条:支持使用标准异常》的引文:
NullPointerException
并不是仅在访问null
引用的成员时才保留;而是在访问null
引用的成员时才保留。当参数为非法值时抛出它们是非常标准的。You can use one of the many libraries designed to facilitate precondition checks. Many code in Google Guava uses
com.google.common.base.Preconditions
It has
checkNotNull
that is used extensively within Guava. You can then write:Most methods are overloaded to either take no error message, a fixed error message, or a templatized error message with varargs.
On
IllegalArgumentException
vsNullPointerException
While your original code throws
IllegalArgumentException
onnull
arguments, Guava'sPreconditions.checkNotNull
throwsNullPointerException
instead.Here's a quote from Effective Java 2nd Edition: Item 60: Favor the use of standard exceptions:
A
NullPointerException
isn't reserved for just when you access members of anull
reference; it's pretty standard to throw them when an argument isnull
when that's an illegal value.我会有一个实用方法:
我会让它返回对象,以便您可以在这样的作业中使用它:
编辑:关于使用第三方库的建议,Google 先决条件尤其比我的代码做得更好。但是,如果这是将库包含在项目中的唯一原因,我会犹豫。方法太简单了。
I would have a utility method:
I would have it return the object so that you can use it in assignments like this:
EDIT: Regarding the suggestions to use a third party library, the Google Preconditions in particular does the above even better than my code. However, if this is the only reasons to include the library in your project, I'd be hesitant. The method is too simple.
除了上面给出的所有有效且合理的答案之外,我认为最好指出也许检查 null 并不是必要的“良好实践”。 (假设除了 OP 之外的读者可能会认为这个问题是教条的)
来自 Misko Hevery 关于可测试性的博客:
断言或不断言
Apart from the answers given above which are all valid and reasonable, I think it's good to point out that maybe checking for null isn't necessary "good practice". (Assuming readers other than the OP might take the question as dogmatic)
From Misko Hevery blog on testability:
To Assert or Not To Assert
抛出未经检查的异常的替代方法是使用
assert
。否则,我会抛出已检查的异常,以使调用者意识到构造函数无法使用非法值。前两个解决方案之间的区别 - 您是否需要详细的错误消息,您是否需要知道哪个参数失败,或者是否足以知道由于非法参数而无法创建实例?
请注意,第二个和第三个示例无法正确报告两个参数都为空。
顺便说一句 - 我投票支持 (1) 的变体:
An alternative to throwing an unchecked exception would be the usage of
assert
. Otherwise I´d throw checked exceptions to make the caller aware of the fact, that the constructor will not work with illegal values.The difference between your first two solutions - do you need a detailed error message, do you need to know which parameter failed or is it enough to know, that the instance couldn't have been created due to illegal arguments?
Note, that the second and third example can't report correctly that both parameters have been null.
BTW - I vote for a variation of (1):
Java 中检查前提条件的方法比较 - Guava、Apache Commons、Spring Framework、Plain Java 断言,
这是本文的摘要:
http://www .sw-engineering-candies.com/blog-1/comparison-of-ways-to-check-preconditions-in-java
Comparison of Ways to Check Preconditions in Java - Guava vs. Apache Commons vs. Spring Framework vs. Plain Java Asserts
this is summary of this article:
http://www.sw-engineering-candies.com/blog-1/comparison-of-ways-to-check-preconditions-in-java
静态分析的注释也很有用,无论是作为运行时检查的补充还是代替运行时检查。
例如,FindBugs 提供了 @NonNull 注释。
Annotations for static analysis are also useful, either in-addition-to or in-place-of the run-time checks.
FindBugs, for example, provides an @NonNull annotation.
您可以简单地使用一个方法来获取需要验证的所有构造函数参数。此方法会引发异常并显示特定消息,具体取决于哪个参数无效。
您的构造函数调用此方法,如果它通过,它将初始化值。
You can simply have a method which takes all the constructor arguments that you need to validate. This method throws exception with specific message depending on which argument is not valid.
Your constructor calls this method, and if it passes, it initialize values.
我假设您谈论的是 Java 中内置的
assert
。在我看来,使用它并不是一个好主意。因为它可以使用命令行参数打开/关闭。 因此有人说它只能在私有方法中使用。我的导师告诉我不要重新发明轮子!他们的建议是使用图书馆。它们(可能)经过精心设计和测试。当然,您有责任确保您拥有一个高质量的库。
其他人告诉我,Enterprise ppl - 在某些方面 - 是错误的,对于简单的任务,您引入了比所需更多的依赖性。我也可以接受这一点......但这是我的最新经验:
首先我编写了自己的私有方法来检查空参数。这很无聊而且多余。我知道我应该将它放入实用程序类中。但是既然有人已经这样做了,我为什么要首先写它呢?我可以节省时间而不编写单元测试并设计现有的东西。除非你想锻炼或学习,否则我不建议这样做。
我最近开始使用 google 的 guava,我发现 - 以及 apache commons - 一旦你开始使用它们,你就不会只使用单一方法。您会越来越多地发现并使用它。最后,这将使您的代码更短、更易读、更一致且更易于维护。
顺便说一句:根据您的目标,我会使用上面提到的库之一选择 2 或 3...
I assume that you talk about the built in
assert
in Java. In my opinion it's not a really good idea to use it. Since it can be turned on/off using command line parameters. Therefore some says it is only acceptable to use in private methods.My mentors are telling me not to re-invent the wheel! Their advice is to use libraries. They are (probably) well designed and tested. Of course it is your responsibility to make sure you grab a good-quality library.
Others are telling me that Enterprise ppl - in some terms - are wrong and you introduce more dependency - for simple tasks - than required. I can accept that point too... But here is my latest experience:
First I wrote my own private method to check null parameters. It's boring and redundant. I know I should put it into a Utility class. But why should I write it at the first place, when someone has already has done it? I can save time not writing unit test and design an existing stuff. Unless you want to exercise or learn I wouldn't recommend to do so.
I recently started to use google's guava and I find that - along with apache commons - once you start to use them, you won't use just for that one single method. You'll discover and use it more and more. At the end, this'll make your code shorter, more readable, more consistent and more maintainable.
BTW.: Depending on your aims I would go with 2 or 3 using one of the mentioned library above...