参数“foo”不应该被分配 - 有什么害处?

2022-09-01 11:30:59

比较此方法:

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


答案 1

看起来没有人在这里做过诅咒。

我通常不会改变参数,事实上,我倾向于标记我的参数以明确禁止它。几个原因:final

  • 对参数的赋值可能会与尝试将其用作“输出参数”混淆,ref:javapractices.com,清晰度就是一切

  • 支持不可变性,这适用于参数值,就像其他任何东西一样。基元只是同一事物的退化情况,(通常)更容易推理不可变变量。参考、有效 Java 项目 13javapractices.com

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

我不能抽象地明智地谈论你的具体案例,但除非所有其他事情我可能会做不同的事情,否则我会赞成:

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

甚至(假设你不会在只有一个参数的实际方法中处理空值,它必须是更复杂的东西的一部分)...此外,一般来说,接受作为参数的方法应该被显式记录为这样做,即使只是为了加强空参数应该是例外的假设。在第二种方法中,您甚至可以使用@NonNull批注null

/**
  * @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
}

StackOverflow上的相关问题(和相关参数):“在Java中适用时使用最终修饰符......”“方法参数中的最终关键字”,“您是否在Java中最终确定局部变量和方法参数”。


答案 2

有时认为在方法中重新分配参数是一种不好的做法。它可能来自C / C++,其中调用可以在方法完成后更改。但Java的情况并非如此。doSomething(myVar)myVar

恕我直言,如果您将其作为方法中的第一件事,这完全没问题。每个阅读你的代码的人都会明白发生了什么。但是,如果深埋在代码中,可能会令人困惑。


推荐