Groovy 2.5.0で追加されたgroovy.transform.AutoFinalを試してみた
最新のGroovy 2.5.0から、groovy.transform.AutoFinal
というAST変換が追加されていたらしい。
ついさっきPaul King氏のツイートを目にして初めて知った。
I agree with you. In Groovy, we added @AutoFinal to add them implicitly for those that want them but don't want to see them.
— Paul King (@paulk_asert) 2018年9月13日
気になったので早速試してみた。
まずは@AutoFinal
なし。
class Person { String firstName String lastName Person(String firstName, String lastName) { lastName = lastName.toUpperCase() // あえてパラメータに再代入する(普通はこんなことしちゃダメ) this.firstName = firstName this.lastName = lastName } String toString() { "$firstName $lastName" } } def p = new Person("Nobunaga", "Oda") assert p.toString() == "Nobunaga ODA"
普通に実行できる。
で、クラスに@AutoFinal
アノテーションをつけてみる。
import groovy.transform.* @AutoFinal // <--- これを追加しただけ class Person { String firstName final String lastName Person(String firstName, String lastName) { lastName = lastName.toUpperCase() // あえてパラメータに再代入する(普通はこんなことしちゃダメ) this.firstName = firstName this.lastName = lastName } String toString() { "$firstName $lastName" } } def p = new Person("Nobunaga", "Oda") assert p.toString() == "Nobunaga ODA"
これを実行しようとすると、
1 compilation error: The parameter [lastName] is declared final but is reassigned
と、コンパイルエラーになった。
というように、@AutoFinal
をつけると、AST変換によって全てのコンストラクタ引数、メソッド引数、クロージャ引数に暗黙のfinalが付与されて、コンパイルチェックされるようになる。
これはいいかもしれない。
(おまけ) プロパティのfinal
化=不変化
なお、
import groovy.transform.* @AutoFinal class Person { String firstName String lastName Person(String firstName, String lastName) { //lastName = lastName.toUpperCase() // このエラーは今は興味ないのでコメントアウト this.firstName = firstName this.lastName = lastName } String toString() { "$firstName $lastName" } } def p = new Person("Nobunaga", "Oda") assert p.toString() == "Nobunaga Oda" // プロパティは再代入可能 p.firstName = "Nobunari" assert p.toString() == "Nobunari Oda"
は普通に実行できる。つまりプロパティは再代入可能なままなので注意。
プロパティを再代入不可能にするには、groovy.transform.Immutable
という前からあるAST変換を使えばOK。
簡単に不変オブジェクトにできる。
import groovy.transform.* @Immutable class Person { String firstName String lastName // @Immutableを使った場合は、Mapを受け取るコンストラクタと // プロパティ定義順にしたがって全部受け取るコンストラクタが自動生成される。 // 明示的なコンストラクタを実装するとエラーになる。 // Error during ImmutableBase processing. Explicit constructors not allowed for class: Person // //Person(String firstName, String lastName) { // //lastName = lastName.toUpperCase() // このエラーは今は興味ないのでコメントアウト // this.firstName = firstName // this.lastName = lastName //} String toString() { "$firstName $lastName" } } def p = new Person("Nobunaga", "Oda") assert p.toString() == "Nobunaga Oda" // プロパティは再代入不可能になる p.firstName = "Nobunari" assert p.toString() == "Nobunari Oda"
groovy.lang.ReadOnlyPropertyException: Cannot set readonly property: firstName for class: Person
コンパイルエラーではなく、実行時に例外が発生する点がちょっと違う。