虽然我了解final关键字在类和方法的上下文中的用途以及其在变量方面的使用意图;但是,我刚刚开始从事的项目似乎数量过多,我对其背后的逻辑感到好奇。

下面的代码片段只是我的一个简短示例在finalkey变量的value关键字中看不到什么要点:

private <K, V> Collection<V> getValuesForKeys(
    final Map<K, V> map, final Collection<K> keys) 
{
    final Collection<V> values = new ArrayList<V>(keys.size());
    for (final K key : keys) {
        final V value = map.get(key);
        if (value != null) {
            values.add(value);
        }
    }
    return values;
}


我一直在通过我通过Google找到的文章来阅读用法;但是,该模式是否真的可以帮助编译器优化代码?

评论

只是把它扔在那里-但是我已经在项目中进行了约定,以便在适当的地方使用final,所以我通常会设置eclipse或netbeans来将它们添加到文件的保存操作中。这可能就是为什么它们看起来“过多”的原因-他们也总是对我这样做。我真的需要担心引用在初始化,使用和丢弃的两行中是否不变吗?

steve-yegge.blogspot.com/2010/07/…

密切相关:programmers.stackexchange.com/questions/48413/…

#1 楼

有许多参考资料表明对final的自由使用。 Java语言规范甚至还介绍了有关最终变量的部分。静态分析工具中的各种规则也支持此功能-PMD甚至具有许多规则来检测何时可以使用final。我链接的页面提供了有关final的功能以及您为什么应该自由使用它的许多要点。可能促使您的代码示例的作者使用它的原因:


它使代码的意图更加清晰,并导致了自我记录代码。使用final可以防止原始对象的值更改或创建新对象并覆盖现有对象。如果不需要更改变量的值而有人更改了,IDE和/或编译器将提供警告。开发人员必须解决问题或从变量中明确删除final修饰符。无论哪种方式,都必须考虑以确保达到预期的结果。
根据您的代码,它可以为编译器潜在地启用优化提供提示。这与编译时间无关,而是编译器在编译期间可以做什么。也不能保证做任何事情。但是,向编译器发信号通知该变量或该变量引用的对象的值将永远不会改变可能会导致性能优化。

还有其他与并发有关的优点。在类或方法级别应用时,必须确保可以覆盖或继承什么。但是,这些超出了代码示例的范围。再次,我链接的文章将更深入地介绍如何应用final

确保代码作者决定使用final的唯一方法是找到作者并问自己。

评论


Scala聪明地使val(对于不可变变量)和var(对于可变变量)的长度完全相同。

–肯·布鲁姆
2011年8月4日23:46



通过语言语义而不是flimsey注释表达意图的能力是良好语言设计(IMO)的关键

–马丁·约克
2011年8月8日17:56

对不起,但我必须在两点上都不同意。 1)自由使用'final'(IMHO)只会使代码混乱,而不会增加价值,因为如果使用频率太高,它会成为习惯,而不是有预谋的意图; 2)过早的优化是您应与导师私下讨论的一个问题,这不是应该在公共代码中播放的内容。

– Paul Smith
16年5月16日在15:01

如果编译器可以发现分配违反了final,那么即使没有明确标记为final,它也可以得出何时可以优化分配,就好像是final。

–苗条
16年5月24日在8:29

在Java中,使用final会给代码增加很多噪音。在Swift中,您必须在“ let”和“ var”或Scala(必须在“ val”和“ var”之间选择)之间进行选择,噪声方面已经消失了,因此我希望开发人员在可能的情况下始终使用常数形式。

– gnasher729
16年8月1日在18:33

#2 楼

在我看来,“最终”的主要好处有两个方面:


最终变量比非最终变量“更安全”,因为一旦绑定在一起,就再也没有问题了他们目前的状态是什么。
由于上述原因,使变量为final可以减轻程序员的过多心理负担-他/她不必浏览代码即可查看变量是否已更改。任何在功能语言环境中花费过任何时间的人都会熟悉这种愉快的事态。

对于这个特定的示例,可能是程序员选择了“最终”习惯于顺理成章地在所有地方应用“最终”关键字。 (我对final关键字在谈论单个分配时会帮助编译器的想法表示怀疑–当然,确定只发生一个分配不需要它吗?)

Java倒退的观点-变量不应有“ final”关键字,默认情况下,所有内容都应为“ final”,如果要使用可变变量,则必须为此添加一个关键字(“ var”或某些这样)。 (正如另一位评论者所述,scala有两个关键字-“ val”和“ var”分别用于最终变量和非最终变量-我将接受它。)

评论


+1同意决赛应该是相反的方式。不幸的是,他们想要C语法。

–user1249
11年8月8日在17:23

绝对同意这应该是另一回事。我的编码风格使用了很多可能是最终的东西,但我没有使它最终定下来,因为它会使代码看起来混乱而混乱。我尽力使方法简短,以使显而易见。

–亚当·贾斯基维奇(Adam Jaskiewicz)
11年8月8日在17:44

+1表示“我认为Java会倒退...”-完全不同意

–贪婪
2014年9月14日,0:44

final不会使非原始对象不变,只是使引用不变。因此,了解状态是第一点是错误的。您知道引用从未绑定到其他对象,但是状态是完全可变的。

– starflyer
18年3月15日在22:37

绝对同意Java / C#将其倒退。我更喜欢F#样式,默认情况下,let是不可变的,并且要求开发人员在他们希望某些东西变得可变时显式地编写let可变的。默认情况下,对象中的所有字段也应该是不可变的,例如F#记录类型,以便状态是真正的“最终”,而不仅仅是引用。

–亚伦·艾希巴赫(Aaron M. Eshbach)
19-09-24在12:48



#3 楼

在Java中,据我所知,唯一需要final关键字的地方是使变量可靠地用于匿名类(因为编译器在幕后进行了一些欺骗,要求该值不能更改)。

据我所知,有一个神话是,final关键字允许Java编译器优化代码,因为所有重要的优化都在运行时的JIT部分发生。

因此,味道。但是,使用大量的finals有一个非常重要的好处,那就是使代码易于将来的维护者阅读。

将变量标记为final告诉读者该变量在分配时永远不会改变。这一点在读取代码时非常重要,因为您知道需要知道变量的值与初始赋值时的值相同,并且不必在脑海中解析所有代码以查看是否再次赋值,这非常重要还有其他的东西。

此外,如果您发现没有用final标记变量,您将知道它会进一步更改!这是一条非常重要的信息,只需丢失五个字符就可以传达给读者。

能帮助维护人员更快,更可靠地完成工作的任何事情都意味着该应用程序是便宜维护!换句话说,final可以节省真金白银。

注意:Eclipse具有“源清理”选项,可以在可能的情况下插入结尾。这对于编写新代码和维护旧代码(插入final,如果缺少一些final,在初始赋值后更改变量)都可能有帮助。我的直觉是,这就是原始作者发现并决定使用的。

在https://stackoverflow.com/q/316352/53897
上对该主题进行了进一步讨论。

评论


final,尽管不是实例变量,但有时确实通过内联方法防止了动态绑定的开销。这样可以避免在CPU上分支。在Java中,除非您指定final,否则支持多态,而在c ++和c#中,除非您指定virtual,否则不支持。在现代CPU上,这并不是真正重要的事情。无论如何,您是正确的,它不会优化实例变量。

–乔纳森·汉森(Jonathan Henson)
2011年8月11日18:42

现代JVM可以自动执行此操作,而无需提示final。

–user1249
2012年1月9日14:57

+1表示“此外,如果您看到未用final标记变量,您将知道它会进一步更改”。这是imo的真正好处。

– Teimpz
16年6月11日在17:43

关于“神话”,这不是Java 5之前的神话(我认为)。如果变量“为final”但没有关键字,则Java 6+不需要final来优化代码。

– Martin Marconcini
16年11月14日在16:18

#4 楼

我认为答案比其他人建议的要简单。这与意图或设计无关。早在很久以前,确实在某些地方(尤其是对于方法和类)添加final允许JVM更加积极地进行优化。结果,有些人发疯,最终将字面意义放在任何地方,以尝试使他们的代码更快地运行。

我要补充的是,优化不是由编译器而是由JVM进行的。此外,我怀疑将final放在局部变量上是否会对性能产生任何影响。

最后,由于JVM优化有所进步,因此使用final可能不会有太大改变。 >

评论


“我怀疑将final放在局部变量上是否会对性能产生任何影响”-我知道的大多数JVM(据我所知有点过时)都使用Tree-SSA数据结构作为中间表示。所有分配都产生一棵新的SSA树,因此这是一个安全的假设。当他们进行优化时,他们甚至不知道它引用了哪个变量引用。

–ccoakley
2011年8月8日在20:30

“我怀疑”->“我还没测量...”

–user1249
2012年1月9日14:55