为什么我应该在 Java 中的方法参数上使用关键字“final”?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/500508/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why should I use the keyword "final" on a method parameter in Java?
提问by
I can't understand where the final
keyword is reallyhandy when it is used on method parameters.
我无法理解在方法参数上使用该final
关键字时,它的真正用处是什么。
If we exclude the usage of anonymous classes, readability and intent declaration then it seems almost worthless to me.
如果我们排除匿名类的使用、可读性和意图声明,那么在我看来几乎毫无价值。
Enforcing that some data remains constant is not as strong as it seems.
强制某些数据保持不变并不像看起来那么强大。
If the parameter is a primitive then it will have no effect since the parameter is passed to the method as a value and changing it will have no effect outside the scope.
If we are passing a parameter by reference, then the reference itself is a local variable and if the reference is changed from within the method, that would not have any effect from outside of the method scope.
如果参数是一个原始参数,那么它将没有任何效果,因为参数作为值传递给方法并且更改它在范围之外不会产生任何影响。
如果我们通过引用传递参数,那么引用本身就是一个局部变量,如果从方法内部更改引用,则不会在方法范围之外产生任何影响。
Consider the simple test example below. This test passes although the method changed the value of the reference given to it, it has no effect.
考虑下面的简单测试示例。尽管该方法更改了提供给它的引用的值,但该测试通过了,但没有任何效果。
public void testNullify() {
Collection<Integer> c = new ArrayList<Integer>();
nullify(c);
assertNotNull(c);
final Collection<Integer> c1 = c;
assertTrue(c1.equals(c));
change(c);
assertTrue(c1.equals(c));
}
private void change(Collection<Integer> c) {
c = new ArrayList<Integer>();
}
public void nullify(Collection<?> t) {
t = null;
}
回答by Jon Skeet
Yes, excluding anonymous classes, readability and intent declaration it's almost worthless. Are those three things worthless though?
是的,不包括匿名类、可读性和意图声明,它几乎一文不值。这三样东西不值钱吗?
Personally I tend not to use final
for local variables and parameters unless I'm using the variable in an anonymous inner class, but I can certainly see the point of those who want to make it clear that the parameter value itself won't change (even if the object it refers to changes its contents). For those who find that adds to readability, I think it's an entirely reasonable thing to do.
就我个人而言final
,除非我在匿名内部类中使用变量,否则我倾向于不使用局部变量和参数,但我当然可以看到那些想要明确参数值本身不会改变(即使如果它引用的对象改变了它的内容)。对于那些发现这增加了可读性的人来说,我认为这是完全合理的做法。
Your point would be more important if anyone were actually claiming that it didkeep data constant in a way that it doesn't - but I can't remember seeing any such claims. Are you suggesting there's a significant body of developers suggesting that final
has more effect than it really does?
如果有人真的声称它确实以一种它没有的方式保持数据不变,你的观点会更重要- 但我不记得看到任何这样的说法。您是说有大量开发人员认为这final
比实际效果更好吗?
EDIT: I should really have summed all of this up with a Monty Python reference; the question seems somewhat similar to asking "What have the Romans ever done for us?"
编辑:我真的应该用 Monty Python 参考来总结所有这些;这个问题似乎有点类似于问“罗马人为我们做过什么?”
回答by Germán
Using final in a method parameter has nothing to do with what happens to the argument on the caller side. It is only meant to mark it as not changing inside that method. As I try to adopt a more functional programming style, I kind of see the value in that.
在方法参数中使用 final 与调用方参数发生的情况无关。它只是为了将其标记为在该方法内未更改。当我尝试采用更函数式的编程风格时,我看到了其中的价值。
回答by starblue
Personally I don't use final on method parameters, because it adds too much clutter to parameter lists. I prefer to enforce that method parameters are not changed through something like Checkstyle.
我个人不会在方法参数上使用 final,因为它给参数列表增加了太多的混乱。我更喜欢强制方法参数不会通过 Checkstyle 之类的东西改变。
For local variables I use final whenever possible, I even let Eclipse do that automatically in my setup for personal projects.
对于我尽可能使用 final 的局部变量,我什至让 Eclipse 在我的个人项目设置中自动执行此操作。
I would certainly like something stronger like C/C++ const.
我当然喜欢像 C/C++ const 这样更强大的东西。
回答by Michael Borgwardt
Let me explain a bit about the one case where you haveto use final, which Jon already mentioned:
让我解释一下你必须使用 final的一种情况,Jon 已经提到过:
If you create an anonymous inner class in your method and use a local variable (such as a method parameter) inside that class, then the compiler forces you to make the parameter final:
如果在方法中创建匿名内部类并在该类中使用局部变量(例如方法参数),则编译器会强制您将参数设为 final:
public Iterator<Integer> createIntegerIterator(final int from, final int to)
{
return new Iterator<Integer>(){
int index = from;
public Integer next()
{
return index++;
}
public boolean hasNext()
{
return index <= to;
}
// remove method omitted
};
}
Here the from
and to
parameters need to be final so they can be used inside the anonymous class.
这里的from
和to
参数需要是最终的,以便它们可以在匿名类中使用。
The reason for that requirement is this: Local variables live on the stack, therefore they exist only while the method is executed. However, the anonymous class instance is returned from the method, so it may live for much longer. You can't preserve the stack, because it is needed for subsequent method calls.
该要求的原因是:局部变量存在于堆栈中,因此它们仅在执行方法时存在。但是,匿名类实例是从该方法返回的,因此它可能存在的时间更长。您不能保留堆栈,因为后续方法调用需要它。
So what Java does instead is to put copiesof those local variables as hidden instance variables into the anonymous class (you can see them if you examine the byte code). But if they were not final, one might expect the anonymous class and the method seeing changes the other one makes to the variable. In order to maintain the illusion that there is only one variable rather than two copies, it has to be final.
因此,Java 所做的就是将这些局部变量的副本作为隐藏的实例变量放入匿名类中(如果您检查字节码,就可以看到它们)。但是如果它们不是最终的,人们可能会期望匿名类和方法看到另一个人对变量所做的更改。为了维持只有一个变量而不是两个副本的错觉,它必须是最终的。
回答by Fortyrunner
I use final all the time on parameters.
我一直在参数上使用 final 。
Does it add that much? Not really.
加那么多吗?并不真地。
Would I turn it off? No.
我会关掉它吗?不。
The reason: I found 3 bugs where people had written sloppy code and failed to set a member variable in accessors. All bugs proved difficult to find.
原因:我发现了 3 个错误,其中人们编写了草率的代码并且未能在访问器中设置成员变量。所有的错误都被证明很难找到。
I'd like to see this made the default in a future version of Java. The pass by value/reference thing trips up an awful lot of junior programmers.
我希望看到这在 Java 的未来版本中成为默认设置。传递值/引用的事情绊倒了很多初级程序员。
One more thing.. my methods tend to have a low number of parameters so the extra text on a method declaration isn't an issue.
还有一件事..我的方法的参数数量往往很少,因此方法声明上的额外文本不是问题。
回答by Jerry Sha
Sometimes it's nice to be explicit (for readability) that the variable doesn't change. Here's a simple example where using final
can save some possible headaches:
有时,明确(为了可读性)变量不会改变是很好的。这是一个简单的例子,使用final
可以避免一些可能的麻烦:
public void setTest(String test) {
test = test;
}
If you forget the 'this' keyword on a setter, then the variable you want to set doesn't get set. However, if you used the final
keyword on the parameter, then the bug would be caught at compile time.
如果您忘记了 setter 上的“this”关键字,那么您想要设置的变量不会被设置。但是,如果您在final
参数上使用关键字,那么该错误将在编译时被捕获。
回答by Michael Rutherfurd
One additional reason to add final to parameter declarations is that it helps to identify variables that need to be renamed as part of a "Extract Method" refactoring. I have found that adding final to each parameter prior to starting a large method refactoring quickly tells me if there are any issues I need to address before continuing.
将 final 添加到参数声明的另一个原因是它有助于识别需要重命名为“提取方法”重构的一部分的变量。我发现在开始大型方法重构之前将 final 添加到每个参数可以快速告诉我在继续之前是否需要解决任何问题。
However, I generally remove them as superfluous at the end of the refactoring.
但是,我通常在重构结束时将它们删除为多余的。
回答by Basil Bourque
Stop a Variable's Reassignment
停止变量的重新分配
While these answers are intellectually interesting, I've not read the short simple answer:
虽然这些答案在智力上很有趣,但我没有阅读简短的简单答案:
Use the keyword finalwhen you want the compiler to prevent a variable from being re-assigned to a different object.
当您希望编译器防止将变量重新分配给不同的对象时,请使用关键字final。
Whether the variable is a static variable, member variable, local variable, or argument/parameter variable, the effect is entirely the same.
无论变量是静态变量、成员变量、局部变量,还是实参/参量变量,效果都是完全一样的。
Example
例子
Let's see the effect in action.
让我们看看实际效果。
Consider this simple method, where the two variables (argand x) can both be re-assigned different objects.
考虑这个简单的方法,其中两个变量(arg和x)都可以重新分配不同的对象。
// Example use of this method:
// this.doSomething( "tiger" );
void doSomething( String arg ) {
String x = arg; // Both variables now point to the same String object.
x = "elephant"; // This variable now points to a different String object.
arg = "giraffe"; // Ditto. Now neither variable points to the original passed String.
}
Mark the local variable as final. This results in a compiler error.
将局部变量标记为final。这会导致编译器错误。
void doSomething( String arg ) {
final String x = arg; // Mark variable as 'final'.
x = "elephant"; // Compiler error: The final local variable x cannot be assigned.
arg = "giraffe";
}
Instead, let's mark the parameter variable as final. This too results in a compiler error.
相反,让我们将参数变量标记为final。这也会导致编译器错误。
void doSomething( final String arg ) { // Mark argument as 'final'.
String x = arg;
x = "elephant";
arg = "giraffe"; // Compiler error: The passed argument variable arg cannot be re-assigned to another object.
}
Moral of the story:
故事的道德启示:
If you want to ensure a variable always points to the same object, mark the variable final.
如果要确保变量始终指向同一个对象,请将变量标记为final。
Never Reassign Arguments
永远不要重新分配参数
As good programming practice (in any language), you should neverre-assign a parameter/argument variable to an object other than the object passed by the calling method. In the examples above, one should never write the line arg =
. Since humans make mistakes, and programmers are human, let's ask the compiler to assist us. Mark every parameter/argument variable as 'final' so that the compiler may find and flag any such re-assignments.
由于良好的编程习惯(用任何语言),你应该永远不会重新分配参数/参数变量不是由调用方法传递的对象以外的对象。在上面的例子中,永远不要写一行arg =
。既然人会犯错,而程序员也是人,那就让编译器来帮助我们吧。将每个参数/参数变量标记为“最终”,以便编译器可以找到并标记任何此类重新分配。
In Retrospect
回想起来
As noted in other answers… Given Java's original design goal of helping programmers to avoid dumb mistakes such as reading past the end of an array, Java should have been designed to automatically enforce all parameter/argument variables as 'final'. In other words, Arguments should not be variables. But hindsight is 20/20 vision, and the Java designers had their hands full at the time.
正如其他答案中所述……鉴于 Java 的最初设计目标是帮助程序员避免诸如读取数组末尾的愚蠢错误,Java 应该被设计为自动将所有参数/参数变量强制为“最终”。换句话说,Arguments 不应该是 variables。但事后看来是 20/20 的愿景,Java 设计者当时忙得不可开交。
So, always add final
to all arguments?
那么,总是添加final
到所有参数?
Should we add final
to each and every method parameter being declared?
我们应该添加final
到每个被声明的方法参数吗?
- In theory, yes.
- In practice, no.
? Addfinal
only when the method's code is long or complicated, where the argument may be mistaken for a local or member variable and possibly re-assigned.
- 理论上,是的。
- 在实践中,没有。
?final
仅当方法的代码很长或很复杂时才添加,其中参数可能被误认为是局部变量或成员变量并可能重新分配。
If you buy into the practice of never re-assigning an argument, you will be inclined to add a final
to each. But this is tedious and makes the declaration a bit harder to read.
如果您接受从不重新分配参数的做法,您将倾向于final
为每个参数添加一个。但这很乏味,并且使声明更难阅读。
For short simple code where the argument is obviously an argument, and not a local variable nor a member variable, I do not bother adding the final
. If the code is quite obvious, with no chance of me nor any other programmer doing maintenance or refactoring accidentally mistaking the argument variable as something other than an argument, then don't bother. In my own work, I add final
only in longer or more involved code where an argument might mistaken for a local or member variable.
对于参数显然是参数而不是局部变量或成员变量的简短简单代码,我不费心添加final
. 如果代码很明显,我或其他任何程序员都没有机会进行维护或重构,不小心将参数变量误认为不是参数,那么请不要打扰。在我自己的工作中,我final
只添加更长或更复杂的代码,其中参数可能会被误认为是局部变量或成员变量。
Another case added for the completeness
为完整性添加了另一个案例
public class MyClass {
private int x;
//getters and setters
}
void doSomething( final MyClass arg ) { // Mark argument as 'final'.
arg = new MyClass(); // Compiler error: The passed argument variable arg cannot be re-assigned to another object.
arg.setX(20); // allowed
// We can re-assign properties of argument which is marked as final
}
回答by Chris Milburn
I never use final in a parameter list, it just adds clutter like previous respondents have said. Also in Eclipse you can set parameter assignment to generate an error so using final in a parameter list seems pretty redundant to me. Interestingly when I enabled the Eclipse setting for parameter assignment generating an error on it caught this code (this is just how I remember the flow, not the actual code. ) :-
我从不在参数列表中使用 final,它只会像以前的受访者所说的那样增加混乱。同样在 Eclipse 中,您可以设置参数分配以生成错误,因此在参数列表中使用 final 对我来说似乎是多余的。有趣的是,当我为参数分配启用 Eclipse 设置时,在它上面产生了一个错误,它捕获了这个代码(这就是我记住流程的方式,而不是实际的代码。):-
private String getString(String A, int i, String B, String C)
{
if (i > 0)
A += B;
if (i > 100)
A += C;
return A;
}
Playing devil's advocate, what exactly is wrong with doing this?
顶天立地,这样做到底有什么错?
回答by Lawrence
Since Java passes copies of arguments I feel the relevance of final
is rather limited. I guess the habit comes from the C++ era where you could prohibit reference content from being changed by doing a const char const *
. I feel this kind of stuff makes you believe the developer is inherently stupid as f*** and needs to be protected against truly every character he types. In all humbleness may I say, I write very few bugs even though I omit final
(unless I don't want someone to override my methods and classes). Maybe I'm just an old-school dev.
由于 Java 传递参数的副本,我觉得 的相关性final
相当有限。我猜这个习惯来自 C++ 时代,您可以通过执行const char const *
. 我觉得这种东西让你相信开发人员本质上是愚蠢的,需要保护他输入的每个角色。我可以谦虚地说,即使我省略了,我也写了很少的错误final
(除非我不希望有人覆盖我的方法和类)。也许我只是一个老派的开发者。