NULL参数是一种不好的做法吗?

27

将NULL参数传递给方法是否是一种不好的实践,换句话说,我们是否应该拥有允许NULL参数作为有效参数的方法定义。

假设我想要两个方法: 1. 检索所有公司的列表 2. 根据筛选条件检索公司列表

我们可以像下面这样拥有两个方法:

    List<Company> getAllCompaniesList();
    List<Company> getCompaniesList(Company companyFilter);

或者我们可以有一个单一的方法

    List<Company> getCompaniesList(Company companyFilter);

在第二种情况下,如果参数为NULL,则该方法返回所有公司的列表。

除了好实践问题外,我还发现后一种方法存在另一个问题,如下所述。

我正在实现Spring AOP,在其中我希望对参数进行一些检查,例如 1. 参数是否为NULL? 2. 集合大小为0吗?

有些情况下我们根本不能有空参数,比如对于某个方法。

    void addBranches(int companyId, List<Branch>);

可以通过使用Spring AOP定义以下方法来很好地执行此检查

@Before(argNames="args", value="execution(* *)")
void beforeCall(JoinPoint joinPoint ,Object[] args )
{ 
           foreach(Object obj in args)
           {
                 if(obj == NULL)
                 {
                     throw new Exception("Argument NULL");
                 } 
           }   
}

但我遇到的问题是,由于我定义了一些方法应该接受空参数以实现一个单一方法的多个功能,就像上面提到的 getCompaniesList(Company companyFilter) 方法一样。所以我不能对所有方法统一应用 AOP,也不能在方法名匹配方面使用某些表达式。

如果需要更多信息或者问题描述不够清晰,请告诉我。

感谢阅读我的问题并思考。


1
这是一个风格问题,没有唯一正确的答案。 - Seva Alekseyev
我认为困境始于:“接受一个 NULL 参数用于一个方法的多个功能”,每个方法应只做一件事。在您的示例中,我更喜欢发送过滤器列表,而发送空列表与在您的方法中发送 null 具有相同的效果。 - Enrique Palacio
5个回答

22

我有一个非常简单的规则:

在公共方法中不要允许 null 作为参数或返回值。

我使用 OptionalPreconditions 或 AOP 来强制执行该规则。这个决定已经帮我省下了大量时间,避免了由于 NPE 或奇怪行为导致的 bug 修复。


1
太棒了!作为一名有经验的程序员,我正在学习Java方面的知识,这对我非常有用。 - Duke
1
setLocationRelativeTo(null); ... 我希望Sun/Oracle知道这是一种不好的做法。 - Stepan
但是Bozho说有时允许使用空参数是可以的。你同意吗? - MasterJoe
可选项只是另一种 NULL。如果您认真对待此事,也不应使用可选项。 - Bastian Voigt

21

当存在过多的重载方法时,这样做是可以的。因此,您可以允许某些参数为null,而不是拥有所有的参数组合。但如果您这样做,请明确记录下来。

@param foo foo description. Can be null
在您的情况下,我会使用两种方法,第一种方法使用null参数调用第二个方法。这会使API更易用。
没有严格的界限来限制重载和依赖可空参数的使用,这是一个偏好问题。但请注意,因此您具有最多参数的方法将允许其中一些参数为空,因此也要进行文档说明。
此外,请注意,处理多个构造函数参数的首选方法是通过Builder。所以,不要使用以下方式:
public Foo(String bar, String baz, int fooo, double barr, String asd);

每个参数都是可选的,你可以有:

Foo foo = new FooBuilder().setBar(bar).setFooo(fooo).build();

但是,这样我们就必须为每个参数创建一个方法(除非我们将一些参数分组到一个对象中,例如字符串用户名、字符串密码=对象用户)。这很有用和漂亮,但代码不会太多吗?此外,henning77表示,从实际角度来看,由于可能引起的所有NPE,这种方法并不可行。 - MasterJoe

8

谢谢,如果您已经知道,能否请提供一些好的链接? - Maddy.Shik
空对象模式在某些情况下非常有用,例如在返回集合时,并非所有情况都适用,例如当它是单个对象时,我将返回NULL。 - Maddy.Shik

4
规则是:简单的接口,复杂的实现。
在设计API时,应该考虑客户端代码的使用方式来进行决策。如果你预计会看到以下任一情况:
getAllCompaniesList(null);

或者

if (companyFilter == null) {
    getAllCompaniesList();
} else {
    getAllCompaniesList(companyFilter);
}

如果您这样做,那么您是错的。如果客户端代码在编写时可能会有或者没有过滤器,您应该提供两个入口点;如果该决策可能直到运行时才做出,请允许使用空参数。


1
另一种可行的方法可能是使用一个名为CompanyFilter的接口,其中包含一个companyIsIncluded(Company)方法,该方法接受一个Company并返回true或false,以表示是否应包括任何公司。 Company可以实现该接口,使得companyIsIncluded方法的行为与equals()相同,但很容易就能够创建一个单例CompanyFilter.AllCompanies,其companyIsIncluded()方法将始终返回true。使用这种方法,无需传递null值,只需传递对AllComapnies单例的引用即可。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接