为什么'final'关键字在业界很少使用?[关闭]


14

自从final几年前我发现Java关键字的强大功能以来,它帮助我提高了代码的可读性,因为人们可以轻松地看到什么是只读变量。它也可能对JIT有所帮助,尽管这是非常有限的,但不会造成伤害,尤其是在针对嵌入式设备(例如android平台)时。

但是最重​​要的是,它有助于使设计对更改更健壮,并在其他提交者需要修改代码库时为其提供指导。

但是,在浏览某些JDK源代码时,我从未偶然发现过该关键字,无论是用于类,方法还是变量。这同样适用于我必须审查的各种系统。

有什么原因吗?让一切都从内部变通是常见的设计范式吗?


在微优化中,设置final字段的语义与编写volatile字段的语义相同,然后在以后读取它们时需要具有易读的读取语义,这并不总是您想要的
棘手的

5
@ratchet:我认为这更多是关于使类不可变,就像在函数式编程中一样。
乔纳斯(Jonas)

@Kwebble:也许更重要的是,单个String 实例是不可变的。
MatrixFrog 2011年

Answers:


9

我怀疑您没有看到它的原因是因为JDK被设计为可扩展的(它是构建所有程序的基础)。应用程序代码充分利用它并不少见。我也不希望在库代码中看到很多(因为库通常也是为扩展而设计的)。

尝试看一些好的开源项目,我想您会发现更多的。

与您在Java中看到的相反,在.NET世界中,我多次听到这样的论点sealed:默认情况下,句柄应为(类似于final应用于类),并且开发人员应明确取消密封它。


2
我什至指的是某些JDK类的许多私有或受保护成员,这些成员显然是“生成一次,永不覆盖”对象变量。特别是在秋千包中。那些是“最终”的理想选择,因为在使用组件时用空指针替换将导致错误。
Aurelien Ribon

1
@Aurélien:如果让您感觉更好,.NET Framework中的许多类都是密封的,这让某些希望使用自己的功能扩展框架类的用户感到震惊。但是,可以通过使用扩展方法
罗伯特·哈维

1
我认为这更多的是关于不变性,而不是避免扩展。换句话说,使用finalon字段而不是on方法。不可变的类也可以设计为扩展的。
乔纳斯(Jonas)

15

使用的问题final传达的东西是只读的是,它真的只适用于原始类型一样intchar等所有的Java对象实际上是指使用(种)指针。结果,当您final在对象上使用关键字时,您只是在说引用是只读的,对象本身仍然是可变的。

如果它确实使对象成为只读,则可能已经使用了更多的内容。在C ++中,它的作用恰到好处,const因此,它是一个更有用且使用更广泛的关键字。

我在其中final大量使用关键字的地方是使用参数,以避免诸如此类的事情造成的任何混淆:

public void someMethod(FancyObject myObject) {
    myObject = new FancyObject();
    myObject.setProperty(7);
}
...
public static void main(final String[] args) {
    ...
    FancyObject myObject = new FancyObject();
    someOtherObject.someMethod(myObject);
    myObject.getProperty(); // Not 7!
}

在此示例中,显而易见的是,为什么此方法不起作用,但如果someMethod(FancyObject)又大又复杂,则会引起混乱。为什么不避免呢?

它也是Sun(或我现在认为是Oracle)编码标准的一部分。


1
如果final在Java API类中有更多的用途,则与许多Scala库一样,大多数对象都是不可变的。然后,final在很多情况下,使对象字段成为类是不变的。此设计已在BigDecimal和中使用String
乔纳斯(Jonas)

@Jonas我读到的问题更多是关于schmmd答案中的第4点的问题,因为他说的是“因为人们可以很容易地看到什么是只读变量”,并因此做出了回答。也许我应该在回答中包括这个假设。
吉安(又名Gary)2011年

请记住,有些时候您想重新分配参数。例如,修剪字符串参数。
Steve Kuo

@Steve我通常会在这种情况下创建一个新变量。
吉安(Gyan)加里·巴恩(Gary Buyn)2011年

1
@Gary,至少对我来说,错误/混乱是由于重新分配参数引起的,这种情况很少见。我宁愿拥有混乱的免费代码,并接受重新分配导致错误的参数的机会很小。编写/修改代码时要小心。
Steve Kuo

4

我同意该final关键字可以提高可读性。当对象不可变时,它使理解变得更加容易。但是,在Java中它非常冗长,特别是(在我看来)在参数上使用时。这并不是说人们不应该因为冗长而使用它,而是因为它是冗长的所以他们不使用它。

其他一些语言(例如scala)使进行最终声明(val)变得容易得多。在这些语言中,最终声明可能比变量更常见。

请注意,final关键字有许多不同的用法。您的帖子主要涉及项目2和3。

  1. 最终课程(JLS 8.1.1.2)
  2. 最终字段(JLS 8.3.1.2)
  3. 最终方法(JLS 8.4.3.3)
  4. 最终变量(JLS 4.12.4)

2

首先,正式的Java 代码约定既不赞成也不禁止特定的使用final。也就是说,JDK开发人员可以自由选择他们喜欢的方式。

我看不懂他们的想法,但对我而言,是否使用该选项final一直是我们关注的重点。的事情我是否有足够的时间来彻底专注于代码或不

  • 假设,在我的一个项目中,我们可以承受平均每天花在100行代码上的费用。在这个项目中,我对final垃圾的理解是独特的,它只是使代码中已经清楚表达的东西变得模糊。看起来JDK开发人员也属于这一类。
     
    另一方面,在另一个项目中则完全相反,在该项目中,我们平均花了一个小时编写100行代码。在final那儿,我发现自己用自己的和他人的代码像合着mashine枪一样进行射击-仅仅是因为这是检测在我之前写过这个东西的人的意图的最快方法,并且类似地,也是传达我自己的意图的最快方法稍后将处理我的代码的人。

它也可能对JIT有所帮助,虽然那是非常有限的,但不会造成损害。

上面的推理很滑。过早的优化可能会造成危害;唐纳德·克努斯(Donald Knuth)甚至称其为“万恶之源”。不要让它困住你。写愚蠢的代码


2

最近,我发现Eclipse IDE中“保存操作”功能的乐趣。我可以强迫它重新格式化我的代码,插入缺少的@Override注释,并做一些漂亮的事情,例如,final每次点击时,自动删除表达式中不必要的括号或将关键字自动放置到任何地方ctrl + S。我激活了其中一些触发器,男孩,它有很大帮助!

事实证明,这些触发器中的许多触发器都像对我的代码的快速健全性检查一样。

  • 我打算重写一个方法,但是当我点击时注释没有出现ctrl + s?-也许我在某个地方搞砸了参数类型!
  • 保存时从代码中删除了一些括号?-也许对于程序员来说,这种逻辑表达太困难了,以至于无法快速解决。否则,为什么我要首先添加那些括号?
  • 该参数或局部变量不是final。是否必须改变其价值?

事实证明,变量越少更改,调试时的麻烦就越少。您跟踪某个变量的值有多少次才发现它以某种方式从5变为7?“怎么可能?!” 您会问自己,接下来的几个小时会花时间进入和退出无数种方法,以发现您在逻辑上犯了一个错误。为了修复它,您必须再添加一个标志,几个条件并仔细地在此处和此处更改一些值。

哦,我讨厌调试!每次我运行调试我觉得我的时间不多了,我迫切需要一个时间,使至少一些我儿时的梦想变成真!用调试去死吧!final表示没有更多神秘的价值变化。更多finals =>我的代码中更少的脆弱部分=>更少的bug =>花费更多的时间来做美好的事情!

至于final类和方法,我并不在乎。我喜欢多态。多态性意味着重用意味着更少的代码意味着更少的错误。JVM无论如何都需要进行虚拟化和方法内联,所以我做得很好,因此我认为杀死代码重用的可能性并没有带来可观的性能优势,但我认为这没有价值。


final起初在代码中看到所有这些s会使人分心,并且也需要时间来习惯。我的一些队友看到这么多final关键字仍然感到非常惊讶。我希望在IDE中为它的特殊语法着色设置一个。我很乐意将其切换为某种灰色阴影(例如注释),这样它们在阅读代码时不会过于分散注意力。Eclipse当前为return和所有其他关键字使用单独的颜色,但没有final


1
您也许可以考虑研究OCaml或F#之类的功能语言。这些语言往往需要较少的调试,原因之一是默认情况下所有内容都是只读的。简而言之,一旦分配,功能语言中的变量就不会改变。
亚伯

1
是的,我知道,实际上我有时会编写一些ML代码-这就是我从中得到启发的地方:)这与您使用的语言无关,而与您使用的原理和技术有关。可以使用Haskell和do符号来完成所有命令:)当然,Java并不是以功能风格编写的最佳语言,但是至少它允许您编写健壮的代码- 我真正关心的是。
安德鲁АндрейЛисточкин2011年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.