在变量中将变量标记为final是否有意义?

时间:2011-08-24 14:35:11

标签: optimization groovy final

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

3 个答案:

答案 0 :(得分:17)

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

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

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

   0:   invokestatic    #18; //Method $getCallSiteArray:()[Lorg/codehaus/groovy/runtime/callsite/CallSite;
   3:   astore_1
   4:   ldc #58; //String Hello World
   6:   astore_2
   7:   aload_1
   8:   ldc #59; //int 1
   10:  aaload
   11:  aload_0
   12:  aload_2
   13:  invokeinterface #63,  3; //InterfaceMethod org/codehaus/groovy/runtime/callsite/CallSite.callCurrent:(Lgroovy/lang/GroovyObject;Ljava/lang/Object;)Ljava/lang/Object;
   18:  areturn
   19:  nop

javac优化了astore / aload

没有final

   0:   ldc #2; //String Hello World
   2:   astore_1
   3:   getstatic   #3; //Field java/lang/System.out:Ljava/io/PrintStream;
   6:   aload_1
   7:   invokevirtual   #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   10:  return

使用final

   0:   getstatic   #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   3:   ldc #3; //String Hello World
   5:   invokevirtual   #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   8:   return

所有这一切,如果性能至关重要,Groovy开始时是一个糟糕的选择。内联最终变量不会为您节省使用反射进行方法调用的开销。

答案 1 :(得分:12)

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

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

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

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

答案 2 :(得分:3)

还没有。但它可能在未来,所以我仍然在适当时标记它们。

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