Имеет ли смысл отмечать переменную как final в groovy?

Интересно, как переменные, помеченные как final, интерпретируются Groovy (в 1.8.0, 1.8.1). Я знаю, что это имеет смысл на Java, и можно улучшить производительность и, конечно же, помочь избежать глупых ошибок. Я хотел бы узнать, может ли final помочь java-компилятору оптимизировать программу, написанную в Groovy. Интересно, сохраняют ли трансформаторы Groovy окончательные маркировки для переменных.

Ответ 1

Как Джастин сказал, если для вас важны оптимизация, которую компилятор выполняет для конечных переменных, то вы не должны использовать Groovy.

Однако, если производительность Groovy достаточно хороша, то по-прежнему полезно пометить переменные final по двум причинам:

  • Защита инвариантов вашего класса, то есть убедитесь, что значение значения не может быть изменено после построения объекта. Java применяет это во время компиляции, Groovy только применяет это во время выполнения, но это лучше, чем молчание, позволяющее изменить неизменяемое значение.

  • Документация

    . Пользователи вашего класса могут легко увидеть, какие значения они могут изменить.

Ответ 2

Не кажется, что 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 - это плохой выбор для начала. Вложение конечных переменных не избавит вас от накладных расходов при использовании отражения для вызовов методов.

Ответ 3

пока нет. но это может произойти в будущем, поэтому я по-прежнему отмечаю их, если они соответствуют

http://jira.codehaus.org/browse/GROOVY-1628