为方法参数分配新值是否有问题?

Eclipse有一个选项来警告赋值给方法的参数(在方法内),如:

public void doFoo(int a){ if (a<0){ a=0; // this will generate a warning } // do stuff } 

通常我尝试激活(并注意)几乎所有可用的编译器警告,但在这种情况下,我不确定它是否值得。

我看到了改变方法中参数的合法情况(例如:允许参数“取消设置”(例如null)并自动替换默认值),但很少会导致问题,除非它可能有点混淆在方法中间重新分配参数。

你使用这样的警告吗? 为什么/为什么不呢?

注意:

避免这种警告当然等同于使方法参数final (只有这是编译器错误:-))。 所以这个问题为什么我应该在Java中的方法参数上使用关键字“final”? 可能是相关的。

对我来说,只要你早点清楚地做到这一点,就没事了。 正如你所说的那样,将其深入四个条件中间深入到30行函数中并不理想。

使用对象引用时,显然必须要小心,因为调用给定对象的方法可能会更改其状态并将信息传递给调用者,但当然如果您已经在自己的占位符中填充了该信息,那么没有沟通。

另一方面是声明一个新变量并将参数(或者参数需要默认的默认值)分配给它可能更清晰,并且几乎肯定不会效率低 – 任何体面的编译器(无论是主编译器还是JIT) )在可行时将优化出来。

令人困惑的部分是警告的原因。 如果你在方法中重新赋值参数一个新值(可能是有条件的),那么它就不清楚了,是什么。 这就是为什么它被视为好的风格,让方法 – 参数保持不变。

分配方法参数不是大多数人期望在大多数方法中发生的事情。 由于我们在假设参数值是固定的情况下阅读代码,因此,如果仅通过惯例和最不惊讶原则,赋值通常被视为不良实践。

总是可以选择分配方法参数:通常本地临时副本就可以了。 但一般来说,如果您发现需要通过参数重新分配来控制函数的逻辑,那么它可以从重构到更小的方法中受益。

如果参数是引用类型,则重新分配给方法参数变量通常是错误的。

请考虑以下代码:

 MyObject myObject = new myObject(); myObject.Foo = "foo"; doFoo(myObject); // what's the value of myObject.Foo here? public void doFoo(MyObject myFoo){ myFoo = new MyObject("Bar"); } 

许多人都希望在调用doFoo之后,myObject.Foo将等于“Bar”。 当然,它不会 – 因为Java不是通过引用传递 ,而是通过引用值传递 – 也就是说,引用的副本被传递给方法。 重新分配到该副本只会在本地范围内产生影响,而不会在呼叫站点产生影响。 这是最常被误解的概念之一。

不同的编译器警告可适用于不同的情况。 当然,有些适用于大多数或所有情况,但这似乎不是其中之一。

我会想到这个特殊的警告,因为编译器会为您提供警告,让您在需要时重新分配方法参数,而不是不应重新分配方法参数的规则。 你的例子构成了一个完全有效的案例。

我有时会在这样的情况下使用它:

 void countdown(int n) { for (; n > 0; n--) { // do something } } 

避免在for循环中引入变量i 。 通常我只在非常短的函数中使用这些“技巧”。

就个人而言,我非常不喜欢以这种方式“纠正”函数内部的参数。 我更喜欢通过断言捕捉这些并确保合同是正确的。

我通常不需要为方法参数赋值新值。

至于最佳实践 – 警告还可以避免在面对如下代码时产生混淆:

  public void foo() { int a = 1; bar(a); System.out.println(a); } public void bar(int a) { a++; } 

你应该编写没有副作用的代码:每个方法都应该是一个不会改变的函数 。 否则它是一个命令 ,它可能是危险的。

请参阅DDD网站上的命令和function定义:

function :计算并返回没有可观察副作用的结果的操作。

命令 :对系统进行某些更改的操作(例如,设置变量)。 有意产生副作用的操作。