当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,除非我在匿名内部类中使用变量,但我当然可以看到那些想要明确参数值本身不会改变的人的观点(即使它引用的对象改变了其内容)。对于那些发现这增加了可读性的人来说,我认为这是一件完全合理的事情。

如果有人真的声称它确实以某种方式保持数据不变,那么你的观点将更加重要——但我不记得看到过任何这样的说法。你的意思是有很多开发者认为final的效果比实际效果更大?

编辑:我真的应该用Monty Python的参考来总结所有这些;这个问题似乎有点类似于问“罗马人为我们做过什么?”

其他回答

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

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

简短的回答:最终有一点帮助,但是……在客户端使用防御性编程。

实际上,final的问题在于它只强制引用不变,允许被引用的对象成员发生变化,而调用者不知道。因此,在这方面的最佳实践是在调用方进行防御性编程,创建深度不可变的实例或对象的深度副本,这些实例或对象有被肆无忌惮的api窃取的危险。

是的,除去匿名类、可读性和意图声明,它几乎毫无价值。但这三样东西毫无价值吗?

就我个人而言,我倾向于不对局部变量和参数使用final,除非我在匿名内部类中使用变量,但我当然可以看到那些想要明确参数值本身不会改变的人的观点(即使它引用的对象改变了其内容)。对于那些发现这增加了可读性的人来说,我认为这是一件完全合理的事情。

如果有人真的声称它确实以某种方式保持数据不变,那么你的观点将更加重要——但我不记得看到过任何这样的说法。你的意思是有很多开发者认为final的效果比实际效果更大?

编辑:我真的应该用Monty Python的参考来总结所有这些;这个问题似乎有点类似于问“罗马人为我们做过什么?”

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

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

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

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