在Java中更改参数是一种好的实践吗?

19
假设我正在Java中编写一个名为foo(int i)的方法。
由于i是按值传递的,因此在foo中更改它是安全的。例如:

void foo(int i) {
   i = i + 1; // 改变i的值
   ...
}

在Java中更改方法参数被认为是良好还是不良实践?

6个回答

26

虽然一些人会忽略这一点,但总的来说,这被认为是不好的做法。对于像原始类型这样通过传值直接传递的参数,覆盖原始变量没有任何优势。在这种情况下,建议像@João那样制作一份副本。

对于传递其引用按值(对象)的参数,如果修改句柄以指向不同的对象,那就非常混乱了。这更加重要,因为修改作为参数传递的对象的内容也会修改原始对象。

如果您替换了句柄所引用的对象,然后修改它的内容,则调用方中原始引用所指向的对象将不会被替换,但阅读代码的人可能会期望替换该对象。

而如果您不替换对象,而是修改其内容,则调用您的方法的方法可能不会预期此更改。这类通常属于与安全有关的不良做法。


在Java中,所有东西都是按值传递的。对象不是“传递”的;对象不是值。 - newacct
如果我使用“按值调用”和“按引用调用”这些术语,你会感觉更好吗?另外,“对象不是值”是什么意思? - Rajesh J Advani
3
不是的。Java 中始终采用传值调用(pass-by-value),Java 中的类型只有原始类型和引用类型,因此传递的值只能是原始类型和引用类型。与 C++ 不同的是,你不能拥有一个值“为”对象的变量;你只能拥有一个值为指向对象的引用的变量。所有与对象相关的操作必须通过引用完成——new SomeClass() 会计算得到一个引用;字段和方法访问使用引用。这就是“对象不是值”的含义。你不能“传递”一个对象。 - newacct
4
是的,我阅读了关于这个话题的所有论点,尽管如此,我仍然认为你选择的措辞比有帮助更加令人困惑。我已经重新表述了答案,如果现在看起来可以,请告诉我。 - Rajesh J Advani

8

这只是个人意见,但我认为这可能会令其他想在代码中使用原始参数值的人感到困惑,他们可能没有注意到它已经被更改了。

此外,简单地创建另一个变量并将修改后的值赋给它(即int j = i + 1)非常便宜。


3
我的个人观点与你的不同。不理解一种方法就擅自进行改变是不好的。 - Captain Giraffe
4
@CaptainGiraffe 确实。但是混淆视听会让理解方法变得比必要的困难,并且区分传递进来的值和(由于某种原因)改变的值可以有助于理解。 - user395760
1
世界上的所有观点都是个人观点或企业观点 :) 显然,问题意味着询问一般共识是什么。而这是一个不好的想法。原因在我的答案中已经说明了。 - Rajesh J Advani

3

由于i是按值传递的,所以在foo()中更改它是安全的。

即使您传递了对象引用,也是绝对安全的,因为它们是本地的:即将新引用分配给本地引用不会对调用代码中的原始引用产生任何影响。

这是您个人的选择。然而,我不会更改参数值,因为这可能会使人失去传递给此方法的实际值的跟踪。


真实且值得注意。但你应该将其写在注释中,而不是答案中。同时请注意,OP从未暗示过其他情况。 - user395760
好的。顺便问一下,OP是什么意思?我是新手 :) - srikanth yaradla
没问题。OP = 原帖发布者,即提出这个问题的Michael。 - user395760

2
需要注意的是,i = i + 1; 并没有真正改变 i 的值。它只改变了你本地的 i 副本(换句话说,调用代码中的 i 不会改变)。
基于此,遵循最小惊讶原则 (POLS)有助于提高代码的可读性并避免意外行为。

它会改变本地的 i,但不会改变作为参数传递的原始值,该参数不一定要被称为 i,实际上甚至不必是一个变量。 - user207421

1

这取决于上下文。我倾向于认为这是“不良实践”,原因有两个:

  1. 有些人可能会认为原始值被更改了。
  2. 它可能会使代码更难理解(通过适当缩短方法来减轻这种情况)。

第三个问题出现在引用值时。如果您修改参数引用以指向其他内容并更改其状态,则原始内容将不会被修改-这可能是有意的,也可能不是。如果您创建另一个引用以引用该参数并更改新引用的状态,则参数的引用将被更改-这也可能是有意的,也可能不是。


1
#1不是一个好的理由。如果他们不知道一个方法使用什么样的参数传递方式,那么他们比误解一个方法更糟糕,并且应该在进行任何编码之前先学习它。 - user395760
1
@delnan 这是一个很好的理由 - 在可以避免的情况下,应该尽量避免任何混淆。你可能不同意这个理由,这也没关系。 - Dave Newton
好的,我不同意这个理由。但并不是因为我不避免混淆,而是因为我认为对于实际了解该语言的人来说,它的含义就像 a+1 一样显然。 - user395760

1

中立。但是许多人认为更好的做法是改变方法为:

void foo(final int i) {
    int j = i + 1; // not change i
    ...
}

请随意选择工作方式。


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