为方法参数分配新值是否有问题?
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 :计算并返回没有可观察副作用的结果的操作。
命令 :对系统进行某些更改的操作(例如,设置变量)。 有意产生副作用的操作。