我认为final
方法参数和局部变量是代码噪声。Java方法声明可能会很长(尤其是泛型),因此无需再进行声明。
如果正确编写了单元测试,则将选择分配给“有害”的参数,因此它实际上永远不会成为问题。视觉清晰度比避免可能由于单元测试覆盖范围不足而导致的错误更重要。
如果您对参数或局部变量进行了分配,可以将诸如FindBugs和CheckStyle之类的工具配置为破坏构建,如果您非常在意这些事情的话。
当然,如果您需要使它们最终化(例如,因为您正在使用匿名类中的值),那么没问题-这是最简单的最简单的解决方案。
除了在参数中添加额外的关键字(从而使恕我直言伪装)的明显效果之外,将final添加到方法参数通常会使方法主体中的代码变得不易读,这会使代码变得更糟-成为“好”代码必须可读性和尽可能简单。对于一个人为的例子,说我有一个方法,需要不区分大小写地工作。
没有final
:
public void doSomething(String input) {
input = input.toLowerCase();
// do a few things with input
}
简单。清洁。每个人都知道发生了什么事。
现在使用“最终”选项1:
public void doSomething(final String input) {
final String lowercaseInput = input.toLowerCase();
// do a few things with lowercaseInput
}
尽管使参数final
停止使编码器认为自己使用的是原始值,从而使代码进一步降低,但同样有风险的是,可能会使用更input
深层的代码代替lowercaseInput
,它不应该也不可以防止,因为您可以请将其排除在范围之外(甚至分配null
给input
那是否仍然有帮助)。
使用“最终”选项2:
public void doSomething(final String input) {
// do a few things with input.toLowerCase()
}
现在,我们刚刚产生了更多的代码噪音,并引入了必须调用toLowerCase()
n次的性能问题。
使用“最终”选项3:
public void doSomething(final String input) {
doSomethingPrivate(input.toLowerCase());
}
/** @throws IllegalArgumentException if input not all lower case */
private void doSomethingPrivate(final String input) {
if (!input.equals(input.toLowerCase())) {
throw new IllegalArgumentException("input not lowercase");
}
// do a few things with input
}
谈论代码噪声。这是火车残骸。我们有了一个新方法,一个必需的异常块,因为其他代码可能会错误地调用它。更多的单元测试将涵盖该异常。所有这些都避免了一条简单且恕我直言的可取且无害的路线。
还有一个问题是方法的长度不能太长,以至于您不能轻易地以视觉方式接受它,并且一眼就知道对参数的赋值已经发生。
我确实认为,如果您为参数分配一个参数,则您应该在方法的每个早期阶段(最好是在基本输入检查之后的第一行或第二行)都执行此操作,从而有效地将其替换为整个方法,这是一种很好的做法/风格,方法。读者知道,期望任何分配都是显而易见的(在签名声明附近)并且在一致的位置,这大大减轻了添加final试图避免的问题。实际上,我很少分配参数,但是如果这样做,我总是在方法的顶部进行。
还要注意,final
实际上并没有像乍看起来那样真正地保护您:
public void foo(final Date date) {
date.setTime(0);
// code that uses date
}
final
除非参数类型是原始或不可变的,否则不能完全保护您。