enumの抽象メソッドはgroovyでサポートされてない? #jggug #q
表題の通り。
groovyでenum書いててコンパイルできなかったのでメモ。
(構文ミスってるかと思って何度も確認したので。。。)
前提
javaではenumで抽象メソッドを定義することが可能です。
これにより、新たに値を増やした際に抽象メソッドの実装漏れを防ぐことが可能です。
enum Hoge { HUGA { @Override void method(String name) { } }, PIYO { @Override void method(String name) { } }; abstract void method(String name); }
当然コンパイルも可能。
C:\20130107>dir <略> C:\20130107 のディレクトリ 2013/01/07 20:10 <DIR> . 2013/01/07 20:10 <DIR> .. 2013/01/07 20:11 232 Hoge.java <略> C:\20130107>javac Hoge.java C:\20130107>dir <略> C:\20130107 のディレクトリ 2013/01/07 20:11 <DIR> . 2013/01/07 20:11 <DIR> .. 2013/01/07 20:11 361 Hoge$1.class 2013/01/07 20:11 381 Hoge$2.class 2013/01/07 20:11 943 Hoge.class 2013/01/07 20:11 232 Hoge.java <略>
groovycでコンパイル
拡張子のみ変更してGroovyでコンパイルしようとしたらコンパイルエラー
C:\20130107>dir <略> C:\20130107 のディレクトリ 2013/01/07 20:12 <DIR> . 2013/01/07 20:12 <DIR> .. 2013/01/07 20:11 232 Hoge.groovy <略> C:\20130107>%GROOVY_HOME%/bin/groovyc Hoge.groovy org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed: Hoge.groovy: 1: Can't have an abstract method in a non-abstract class. The class 'Hoge' must be declared abstract or the method 'void method(java.lang.String)' must be implemented. @ line 1, column 1. enum Hoge { ^ Hoge.groovy: 14: Can't have an abstract method in a non-abstract class. The clas s 'Hoge' must be declared abstract or the method 'void method(java.lang.String)' must not be abstract. @ line 14, column 5. abstract void method(String name); ^ 2 errors
抽象メソッドは抽象クラスのみに設定可能だよ!って怒られてるみたい。
javacでコンパイルできたし構文等は間違ってないと思うので、groovyの仕様?
暫定対応
空実装のメソッドを定義してとりあえずの暫定対応。
enum Hoge { HUGA { void method(String name) { } }, PIYO { void method(String name) { } }; void method(String name) { throw new UnsupportedOperationException() } }
C:\20130107>dir <略> C:\20130107 のディレクトリ 2013/01/07 20:12 <DIR> . 2013/01/07 20:12 <DIR> .. 2013/01/07 20:12 280 Hoge.groovy <略> C:\20130107>%GROOVY_HOME%/bin/groovyc Hoge.groovy C:\20130107>dir <略> C:\20130107 のディレクトリ 2013/01/07 20:13 <DIR> . 2013/01/07 20:13 <DIR> .. 2013/01/07 20:13 4,214 Hoge$1.class 2013/01/07 20:13 4,214 Hoge$2.class 2013/01/07 20:13 6,894 Hoge.class 2013/01/07 20:12 280 Hoge.groovy <略>
# 本題からはずれるけどjavacとgroovycで10倍もサイズの差が出るものなのね。
課題
これでもまぁ、とりあえず問題はない。
が、最初に書いた通り値を増やした時にメソッド実装し忘れた場合にコンパイラに怒ってもらいたい所。
その他
↓これ見て
これどうやるの?こんなのない?ってのは、Twitterで聞くよな。
2012年12月 Groovyist/G*のあれやこれや - みちしるべ
#jggug #q みたないなハッシュタグが決まってたほうが拾ってくれる可能性が高まるんだろうな。
ハッシュタグが広まるかどうかが問題だが。
↓こんなん言ったら
追記(2013/01/08)
enumにinterfaceで定義した場合も同様の現象が発生した。
javacでコンパイル
enum Hoge implements IF { HUGA { @Override public void method(String name) { } }, PIYO { @Override public void method(String name) { } }; } interface IF { void method(String name); }
C:\20130108>dir <略> C:\20130108 のディレクトリ 2013/01/08 20:04 <DIR> . 2013/01/08 20:04 <DIR> .. 2013/01/08 20:04 272 Hoge3.java <略> C:\20130108>javac Hoge3.java C:\20130108>dir <略> C:\20130108 のディレクトリ 2013/01/08 20:05 <DIR> . 2013/01/08 20:05 <DIR> .. 2013/01/08 20:05 362 Hoge$1.class 2013/01/08 20:05 382 Hoge$2.class 2013/01/08 20:05 917 Hoge.class 2013/01/08 20:04 272 Hoge3.java 2013/01/08 20:05 129 IF.class <略>
groovycでコンパイル
C:\20130108>dir <略> C:\20130108 のディレクトリ 2013/01/08 20:06 <DIR> . 2013/01/08 20:06 <DIR> .. 2013/01/08 20:04 272 Hoge3.groovy 1 個のファイル 272 バイト 2 個のディレクトリ 3,556,233,216 バイトの空き領域 C:\20130108>%GROOVY_HOME%/bin/groovyc Hoge3.groovy org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed: Hoge3.groovy: 1: Can't have an abstract method in a non-abstract class. The clas s 'Hoge' must be declared abstract or the method 'void method(java.lang.String)' must be implemented. @ line 1, column 1. enum Hoge implements IF { ^ 1 error
暫定対応
この場合も、とりあえずの空実装をenumクラスに追加すればコンパイルはできました。
enum Hoge implements IF { HUGA { @Override void method(String name) { } }, PIYO { @Override void method(String name) { } }; @Override void method(String name) { throw new UnsupportedOperationException() } } interface IF { void method(String name); }
※ ↑のコードをjavacでコンパイルする場合にはpublic付けないとエラーになります。
# blogに書いて気づいたけど、enumの場合はclassと異なるから「Hoge3.java」でenumの名前が「Hoge」でもコンパイルできるんですね。
回答
id:nobeansさんが回答をくれました。
「enumの抽象メソッドはgroovyでサポートされてない?」「Yes. でもそれだけじゃねーんだぜ」 #jggug #q - 豆無日記
上記コードはそのまま使えますが、コンストラクタを呼び出すように設定するとコンパイル云々だけではなくて、メソッドがオーバーライドされないです。
つまり、このコードを実行すると「PIYO」が出力されるはずですが。。。
enum Hoge { HUGA() { @Override void method() { println "HUGA" } }, PIYO() { @Override void method() { println "PIYO" } } void method() { throw new UnsupportedOperationException() } } Hoge.PIYO.method()
「UnsupportedOperationException」が投げられます。
Exception thrown 1 08, 2013 21:06:04 午前 org.codehaus.groovy.runtime.StackTraceUtils sanitize 警告: Sanitizing stacktrace: java.lang.UnsupportedOperationException <略> java.lang.UnsupportedOperationException <略> at ConsoleScript63.run(ConsoleScript63:22)
う〜ん。。。
コンパイルできないならともかく、メソッドがオーバーライドされないのは挙動が異なるわけで。。。
groovyでenum使うのは控えたほうがいいかも?(今は良くても後で抽象メソッド付けるかもしれないし。)