当final关键字用于方法参数时,我不明白它在哪里真正方便。

如果我们排除匿名类的使用,可读性和意图声明,那么它对我来说几乎毫无价值。

强制某些数据保持不变并不像看上去那么有力。

如果参数是一个原语,那么它将没有任何影响,因为参数是作为值传递给方法的,在作用域之外更改它不会产生任何影响。 如果我们通过引用传递参数,那么引用本身就是一个局部变量,如果从方法内部更改引用,那么从方法作用域外部更改引用不会产生任何影响。

考虑下面的简单测试示例。 这个测试通过了,尽管该方法改变了给它的引用值,但它没有任何影响。

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;
}

当前回答

有时显式地(为了可读性)变量不变是很好的。下面是一个简单的例子,使用final可以省去一些麻烦:

public void setTest(String test) {
    test = test;
}

如果你在setter上忘记了'this'关键字,那么你想设置的变量就不会被设置。但是,如果在参数上使用了final关键字,则在编译时就会捕获错误。

其他回答

我从不在参数列表中使用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;
}

唱反调,这样做到底有什么错?

让我来解释一下你必须使用final的一种情况,Jon已经提到过:

如果你在你的方法中创建了一个匿名的内部类,并且在这个类中使用了一个局部变量(比如一个方法参数),那么编译器会强制你将参数设为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
    };
}

这里的from和to参数需要是final,这样它们才能在匿名类中使用。

这种需求的原因是:局部变量存在于堆栈中,因此它们只在方法执行时存在。但是,匿名类实例是从方法返回的,因此它可能存在更长的时间。不能保留堆栈,因为后续的方法调用需要它。

因此,Java所做的是将这些局部变量的副本作为隐藏的实例变量放入匿名类中(如果检查字节代码,您可以看到它们)。但如果它们不是最终的,人们可能会期望匿名类和方法看到另一个对变量所做的更改。为了保持只有一个变量而不是两个副本的错觉,它必须是最终的。

在方法形参中使用final与调用方的实参发生了什么无关。它只是为了将其标记为在该方法中没有更改。当我尝试采用更函数式的编程风格时,我看到了其中的价值。

就我个人而言,我不会在方法参数上使用final,因为它给参数列表增加了太多的混乱。 我更倾向于强制方法参数不通过Checkstyle之类的东西改变。

对于局部变量,我尽可能使用final,我甚至让Eclipse在个人项目的设置中自动执行该操作。

我当然喜欢更强的语言,比如C/ c++ const。

在参数声明中添加final的另一个原因是,它有助于识别作为“Extract Method”重构的一部分需要重命名的变量。我发现,在开始大型方法重构之前向每个参数添加final可以快速告诉我在继续之前是否有任何需要解决的问题。

但是,我通常会在重构结束时将它们作为多余的部分删除。