Java构造函数样式:检查参数不为空
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2997768/
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
Java constructor style: check parameters aren't null
提问by
What are the best practices if you have a class which accepts some parameters but none of them are allowed to be null
?
如果您有一个接受某些参数但不允许任何参数的类,最佳实践是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?
或者是否有更广泛接受的替代方案?
采纳答案by Bozho
The second or the third.
第二个或第三个。
Because it tells the user of your API what exactly went wrong.
因为它会告诉您 API 的用户究竟出了什么问题。
For less verbosity use Validate.notNull(obj, message)
from commons-lang. Thus your constructor will look like:
为了减少冗长,请使用Validate.notNull(obj, message)
commons-lang。因此,您的构造函数将如下所示:
public SomeClass(Object one, Object two) {
Validate.notNull(one, "one can't be null");
Validate.notNull(two, "two can't be null");
...
}
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.
将检查放在 setter 中也是可以接受的,具有相同的冗长注释。如果你的 setter 也有保持对象一致性的作用,你也可以选择第三个。
回答by Marc
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.
您可以简单地拥有一个方法,该方法接受您需要验证的所有构造函数参数。根据哪个参数无效,此方法会抛出带有特定消息的异常。您的构造函数调用此方法,如果它通过,则初始化值。
回答by Andreas Dolk
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.
抛出未经检查的异常的另一种方法是使用assert
. 否则我会抛出检查异常以使调用者意识到构造函数不会处理非法值这一事实。
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):
顺便说一句 - 我投票赞成(1)的变体:
if (one == null || two == null) {
throw new IllegalArgumentException(
String.format("Parameters can't be null: one=%s, two=%s", one, two));
}
回答by Yishai
I would have a utility method:
我会有一个实用方法:
public static <T> T checkNull(String message, T object) {
if(object == null) {
throw new NullPointerException(message);
}
return object;
}
I would have it return the object so that you can use it in assignments like this:
我会让它返回对象,以便您可以在这样的分配中使用它:
public Constructor(Object param) {
this.param = checkNull("Param not allowed to be null", param);
}
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.
编辑:关于使用第三方库的建议,特别是 Google Preconditions 比我的代码做得更好。但是,如果这是将库包含在您的项目中的唯一原因,我会犹豫不决。方法太简单了。
回答by polygenelubricants
You can use one of the many libraries designed to facilitate precondition checks. Many code in Google Guavauses com.google.common.base.Preconditions
您可以使用旨在促进前提条件检查的众多库之一。Google Guava 中的许多代码使用com.google.common.base.Preconditions
Simple static methods to be called at the start of your own methods to verify correct arguments and state. This allows constructs such as
if (count <= 0) { throw new IllegalArgumentException("must be positive: " + count); }
to be replaced with the more compact
checkArgument(count > 0, "must be positive: %s", count);
在您自己的方法开始时调用简单的静态方法以验证正确的参数和状态。这允许构造如
if (count <= 0) { throw new IllegalArgumentException("must be positive: " + count); }
替换为更紧凑的
checkArgument(count > 0, "must be positive: %s", count);
It has checkNotNull
that is used extensively within Guava. You can then write:
它checkNotNull
是内番石榴广泛使用。然后你可以写:
import static com.google.common.base.Preconditions.checkNotNull;
//...
public SomeClass(Object one, Object two) {
this.one = checkNotNull(one);
this.two = checkNotNull(two, "two can't be null!");
//...
}
Most methods are overloaded to either take no error message, a fixed error message, or a templatized error message with varargs.
大多数方法都被重载为不接收错误消息、固定错误消息或带有可变参数的模板化错误消息。
On IllegalArgumentException
vs NullPointerException
在IllegalArgumentException
VSNullPointerException
While your original code throws IllegalArgumentException
on null
arguments, Guava's Preconditions.checkNotNull
throws NullPointerException
instead.
当你的原始代码抛出IllegalArgumentException
的null
论点,番石榴的Preconditions.checkNotNull
抛出NullPointerException
来代替。
Here's a quote from Effective Java 2nd Edition: Item 60: Favor the use of standard exceptions:
这是Effective Java 2nd Edition的引用:第 60 条:赞成使用标准异常:
Arguably, all erroneous method invokations boil down to an illegal argument or an illegal state, but other exceptions are standardly used for certain kindsof illegal argument and states. If a caller passes
null
in some parameter for which null values are prohibited, convention dictatesNullPointerException
be thrown rather thanIllegalArgumentException
.
可以说,所有错误的方法调用都归结为非法参数或非法状态,但其他异常通常用于某些类型的非法参数和状态。如果调用者传入
null
某个禁止使用空值的参数,则约定NullPointerException
将抛出而不是IllegalArgumentException
。
A NullPointerException
isn't reserved for just when you access members of a null
reference; it's pretty standard to throw them when an argument is null
when that's an illegal value.
ANullPointerException
不是只在您访问null
引用成员时保留的;当参数是null
非法值时抛出它们是非常标准的。
System.out.println("some string".split(null));
// throws NullPointerException
回答by Andy Thomas
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.
例如,FindBugs 提供了一个@NonNull 注释。
public SomeClass( @NonNull Object one, @NonNull Object two) {
public SomeClass(@NonNull 对象一,@NonNull 对象二){
回答by qnoid
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)
除了上面给出的所有有效且合理的答案之外,我认为最好指出可能检查 null 不是必要的“良好实践”。(假设 OP 以外的读者可能会认为这个问题是教条的)
From Misko Hevery blog on testability: To Assert or Not To Assert
来自 Misko Hevery 关于可测试性的博客:断言或不断言
回答by uthomas
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.
我假设您谈论的是内置assert
于 Java 中的内容。在我看来,使用它并不是一个好主意。因为它可以使用命令行参数打开/关闭。因此有人说只能在私有方法中使用。
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:
其他人告诉我 Enterprise ppl - 在某些方面 - 是错误的,并且您引入了更多的依赖 - 对于简单的任务 - 比所需的更多。我也可以接受这一点......但这是我的最新经验:
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.
首先,我编写了自己的私有方法来检查空参数。这是无聊和多余的。我知道我应该把它放到一个 Utility 类中。但是,既然有人已经写过了,我为什么还要写呢?我可以节省时间而不是编写单元测试和设计现有的东西。除非你想锻炼或学习,否则我不建议这样做。
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.
我最近开始使用谷歌的番石榴,我发现 - 连同 apache commons - 一旦你开始使用它们,你就不会只使用一种方法。你会越来越多地发现和使用它。最后,这将使您的代码更短、更易读、更一致且更易于维护。
BTW.: Depending on your aims I would go with 2 or 3 using one of the mentioned library above...
顺便说一句:根据你的目标,我会使用上面提到的库之一来使用 2 或 3 ......
回答by nekperu15739
Comparison of Ways to Check Preconditions in Java - Guava vs. Apache Commons vs. Spring Framework vs. Plain Java Asserts
Java 中检查前提条件的方法比较 - Guava vs. Apache Commons vs. Spring Framework vs. Plain Java Asserts
public static void fooSpringFrameworkAssert(String name, int start, int end) {
// Preconditions
Assert.notNull(name, "Name must not be null");
Assert.isTrue(start < end, "Start (" + start + ") must be smaller than end (" + end + ")");
// Do something here ...
}
public static void fooApacheCommonsValidate(String name, int start, int end) {
// Preconditions
Validate.notNull(name, "Name must not be null");
Validate.isTrue(start < end, "Start (%s) must be smaller than end (%s)", start, end);
// Do something here ...
}
public static void fooGuavaPreconditions(String name, int start, int end) {
// Preconditions
Preconditions.checkNotNull(name, "Name must not be null");
Preconditions.checkArgument(start < end, "Start (%s) must be smaller than end (%s)", start, end);
// Do something here ...
}
public static void fooPlainJavaAsserts(String name, int start, int end) {
// Preconditions
assert null != name : "Name must not be null";
assert start < end : "Start (" + start + ") must be smaller than end (" + end + ")";
// Do something here ...
}
this is summary of this article: http://www.sw-engineering-candies.com/blog-1/comparison-of-ways-to-check-preconditions-in-java
这是本文的摘要:http: //www.sw-engineering-candies.com/blog-1/comparison-of-ways-to-check-preconditions-in-java
回答by GhostCat
Old question; another new answer (already mentioned by another comment; but I think worth its own answer).
老问题;另一个新答案(已在另一条评论中提及;但我认为值得自己回答)。
Java 7 added java.lang.Objects.requireNonNull()
to the APIs everybody can use. So checking all arguments for null boils down to a short list like:
Java 7 添加java.lang.Objects.requireNonNull()
到每个人都可以使用的 API 中。因此,检查 null 的所有参数归结为一个简短的列表,例如:
this.arg1 = Objects.requireNonNull(arg1, "arg1 must not be null");
this.arg2 = Objects.requireNonNull(arg2, "arg2 must not be null");
Side notes:
旁注:
- make sure to not reverse the two arguments - the second oneis the message that will be used for the NPE which is thrown if the first argumentis null (if you reverse them, well, then your check will never fail)
- another best practice: if possible, make all your class members final (so you can be sure: when some object has been created successfully, all its members are not null; and they won't change over time)
- 确保不要反转这两个参数 -第二个是将用于 NPE 的消息,如果第一个参数为空,则抛出该消息(如果您反转它们,那么您的检查将永远不会失败)
- 另一个最佳实践:如果可能,将所有类成员设为 final(这样您就可以确定:成功创建某个对象后,其所有成员都不为空;并且它们不会随时间变化)