我读到过,将某些东西标记为final并在循环中使用会带来更好的性能,但这对所有情况都适用吗?我有许多地方没有循环,但我把局部变量标记为final。它会变慢吗,还是仍然可以的?
此外,有些地方我有一个全局变量final(例如android paint),这是否意味着在循环中使用它时不必使其成为局部final变量?
final
变量不太可能对性能产生影响。当你有长方法时,它们可以提高可读性,但我建议将方法拆分为更好的解决方案。
final
字段可能会对性能产生轻微影响,但使其成为final
的更好原因是表明该字段永远不会更改(这也有助于JIT)。final
具有重要的内存语义,可以提高性能(但更重要的是,通常需要使代码正确工作)。您应该尽可能在对象成员上使用final
。然而,对于局部变量,只有在它能提高代码可读性或者当维护者接触到您的代码时可以防止错误时才应使用它。final
会使代码难以阅读。在性能方面,由于局部变量易于分析,因此您不应期望进行任何优化。换句话说,编译器可以自行解决这个问题。根据我的经验,大多数变量可以声明为final
。
然而,这样看起来非常丑陋。这就是我反对它的主要原因。
如果程序的某个部分不是关键性能部分,请谨防过早优化。
在可行的情况下(对于字段和变量,而不是类和方法),使用final被认为是一种良好的编程风格,因为这样可以使测试更加容易。final永远不会对性能产生负面影响。
在性能方面,属性上的final不应该有任何影响。除非:在多线程环境中,多个线程访问同一字段并且“不知道”是否需要重新加载它。对于局部变量的final没有任何影响,因为除了局部作用域之外,没有其他东西可以访问它们。
方法上的final可能会在JIT编译期间产生影响。如果一个方法是final和小的,编译器可以将其内联到循环中,因为明确知道没有人会覆盖它。
我通常根本不使用属性上的final,因为final属性不能轻松地从数据库中加载等。将参数声明为final看起来很丑陋(我从不在代码中分配给它们),但可能会防止由于打字错误而导致的简单错误。然而,如果您开始为变量使用适当的名称,则不太可能犯这样的打字错误。
我认为这不应该是你的首要关注点,正如@perter-lawrey所提到的。首先,编译器优化可以很好地解决问题;其次,有一些工具可以分析您生成的类文件并执行相同的操作,例如ProGuard:Java缩小器、优化器、混淆器和预验证器。
String a = "foo";
if (lol) a += "bar";
for(.. 1000 ...) doSomething(a);
到
final String a;
{
String ma = "foo";
if (lol) ma += "bar";
a = ma;
}
for(.. 1000 ...) doSomething(a);
声明:我不是JIT专家。
最终变量是常量,因此编译器可以生成常量值而不是变量引用指令。当然,这将提高速度(通常也会减小大小)。
还有一些地方我有一个全局变量final(例如android paint),这是否意味着在循环中使用它时不必将其设置为本地final?
抱歉,您的意思是您不需要:
final int somefinalvalue = 0;
void amethod() {
final int somefinalvalue = 0; // repeated from global one
}
还是怎么样?请记住,如果您声明了与全局变量同名的本地变量,那么它将“遮蔽”全局变量。也就是说,它实际上是完全不同的变量。如果您已经有了全局变量,请直接使用它,无需重新声明。
final
和局部变量上的final
是非常不同的。在并发编程中,将字段设置为 final 通常是确保程序正确性的绝对必要条件。 - Enno Shiojifinal
但实际上不是,它的行为将是相同的。将其设置为final
可以明确表明原始类型或引用不会有线程安全问题,因为它不能被更改。注意:所引用的对象仍然可能会发生变化。 - Peter Lawrey