【问题标题】:Does it make sense to mark variable as final in groovy?在 groovy 中将变量标记为 final 是否有意义?
【发布时间】:2011-08-24 14:35:11
【问题描述】:

我想知道标记为 final 的变量如何被 Groovy 解释(在 1.8.0、1.8.1 中)。我知道这在 Java 中是有意义的,并且可以提高性能,而且——当然——有助于避免愚蠢的错误。我想了解 final 是否可以帮助 java 编译器优化用 Groovy 编写的程序。我想知道 Groovy 转换器是否保留了变量的 final 标记。

【问题讨论】:

标签: optimization groovy final


【解决方案1】:

groovyc 似乎不会像 javac 那样内联 final 变量。我创建了两个测试脚本,一个使用 final,一个不使用:

final String message = "Hello World"
println message
String message = "Hello World"
println message

javap -c 为两个类生成了相同的输出:

0:调用静态#18; //方法 $getCallSiteArray:()[Lorg/codehaus/groovy/runtime/callsite/CallSite; 3:astore_1 4:最不发达国家#58; //字符串你好世界 6:astore_2 7:aload_1 8:最不发达国家#59; //int 1 10:加载 11:加载_0 12:加载_2 13:调用接口#63、3; //InterfaceMethod org/codehaus/groovy/runtime/callsite/CallSite.callCurrent:(Lgroovy/lang/GroovyObject;Ljava/lang/Object;)Ljava/lang/Object; 18:返回 19:不

javac 优化掉了astore/aload:

没有final

0:最不发达国家#2; //字符串你好世界 2:astore_1 3:获取静态#3; //字段 java/lang/System.out:Ljava/io/PrintStream; 6:aload_1 7:调用虚拟#4; //方法java/io/PrintStream.println:(Ljava/lang/String;)V 10:返回

final:

0:获取静态#2; //字段 java/lang/System.out:Ljava/io/PrintStream; 3:最不发达国家#3; //字符串你好世界 5:调用虚拟#4; //方法java/io/PrintStream.println:(Ljava/lang/String;)V 8:返回

综上所述,如果性能是最重要的,那么 Groovy 是一个糟糕的选择。内联最终变量不会让您免于使用反射进行方法调用的开销。

【讨论】:

  • 谢谢,关于你的最后一句话,我知道 Groovy 比 Java 或 Scala 慢得多。
【解决方案2】:

作为Justin has said,如果编译器对最终变量执行的优化对您很重要,那么您不应该使用 Groovy。

但是,如果 Groovy 的性能足够好,那么将变量标记为 final 仍然有用,原因有两个:

  • 保护类的不变量,即确保在对象构造后不能更改值。 Java 在编译时强制执行此操作,Groovy 仅在运行时强制执行此操作,但这比静默允许更改不可变值要好

  • 文档。您班级的用户可以轻松查看允许更改哪些值

【讨论】:

  • 当前版本的 Groovy (1.8.2) 不关心 final 并且不强制执行任何操作。
  • 我最近听到很多关于 groovy 如何开始在性能上获得提升的消息。以上是否仍然反映了 Groovy 2.2 或路线图上的版本?
【解决方案3】:

还没有。但将来可能会,所以如果合适的话,我仍然会标记它们。

https://issues.apache.org/jira/browse/GROOVY-1628

【讨论】:

    猜你喜欢
    • 2012-10-20
    • 1970-01-01
    • 2018-10-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-25
    • 2019-03-06
    相关资源
    最近更新 更多