不应分配参数“ foo”,这有什么害处?


问题内容

比较这种方法:

void doStuff(String val) {
    if (val == null) {
        val = DEFAULT_VALUE;
    }

    // lots of complex processing on val
}

…对此方法:

void doStuff(String origVal) {
    String val = origVal;
    if (val == null) {
        val = DEFAULT_VALUE;
    }

    // lots of complex processing on val
}

对于前一种方法,Eclipse发出警告“不应分配参数’val’”。为什么?

在我看来,前者更清洁。一方面,这并不会迫使我想出 两个 好名字val(想出一个好名字已经够难了)。

(注意:假定val在封闭的类中没有命名字段。)


问题答案:

看起来好像没有人在这里做过举动。

我通常不会更改参数,实际上,我倾向于标记我的参数final以明确禁止使用它。原因如下:

  • 分配参数可能会 与尝试将其用作“输出参数” 混淆,请参见javapractices.com,清晰度就是一切

  • 支持不可变性 ,这和其他任何参数一样适用于参数值。基元只是同一事物的简并案例,(通常)更容易推断出不可变的变量。参考,有效的Java项目13javapractices.com

  • 最后(NPI), 自由使用finaljavapractices.com。无论它在参数签名中是多么丑陋,我相信它都倾向于识别意外错误,并且突出显示了可变变量,通常应该是例外。在大多数代码中,大多数可变变量都是出于懒惰,或者是认为它对性能有一定影响,因此,如果明智地选择,不变和命名良好的中间计算,则更清晰,更易于阅读和验证,并且可以针对性能进行干净优化没有您的帮助。

我不能抽象地对您的特定情况进行明智地讲,但是除非我可能做不同的其他所有事情,否则我赞成:

void doStuff(final String origVal)
{
    final String valOrDefault = (origVal == null) ? DEFAULT_VALUE : origVal;
    //lots of complex processing on valOrDefault 
}

甚至(假设在一个只有一个参数的实数方法中您将无法处理空值,它必须是更复杂的东西的一部分)…而且,通常,接受null为参数的方法应明确记录为:这样做,仅仅是为了加强这样的假设,即空参数应该是例外。在第二种方法中,您甚至可以使用@NonNull注解

/**
  * @param origVal string giving value, possibly null, in which case DEFAULT_VALUE is assigned
  */
void doStuff(final String origVal, ... )
{
    final String valOrDefault = (origVal == null) ? DEFAULT_VALUE : origVal; 
    // similar mucking about to make all the parameters behave, separate from
    // actually operating on them...
    ...
    reallyDoStuff(valOrDefault,...);
}

private void reallyDoStuff(final String value, ...)
{
   assert (value != null);
   // do your complex processing
}