Java 构造函数样式:检查参数不为 null

2022-08-31 12:19:31

如果您有一个接受某些参数但都不允许的类,那么最佳实践是什么?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");
        }
        //...
     }
  }

这些样式中哪一种最好?

还是有一种更被广泛接受的替代方案?


答案 1

第二个或第三个。

因为它告诉API的用户到底出了什么问题。

为了减少冗长,请使用 commons-lang。因此,您的构造函数将如下所示:Validate.notNull(obj, message)

public SomeClass(Object one, Object two) {
    Validate.notNull(one, "one can't be null");
    Validate.notNull(two, "two can't be null");
    ...
}

将检查放在 setter 中也是可以接受的,具有相同的详细注释。如果您的 setter 也具有保持对象一致性的作用,您也可以选择第三个。


答案 2

老问题;另一个新答案(另一条评论已经提到过;但我认为值得自己回答)。

Java 7被添加到每个人都可以使用的API中。因此,检查 null 的所有参数可归结为一个简短的列表,例如:java.util.Objects.requireNonNull()

this.arg1 = Objects.requireNonNull(arg1, "arg1 must not be null");
this.arg2 = Objects.requireNonNull(arg2, "arg2 must not be null");

附注:

  • 确保不要反转两个参数 - 第二个是将用于NPE的消息,如果第一个参数为空,则会引发NPE(如果您反转它们,那么您的检查永远不会失败)
  • 另一个最佳实践:如果可能的话,使所有类成员成为最终成员(这样你就可以确定:当某个对象成功创建时,它的所有成员都不是空的;它们不会随着时间的推移而改变)