皆さんはJavaでEnumを使っていますか?
そしてEnum(列挙型)を使いこなせていますか?
「Enumの基本的な使い方はわかるけど値を元に各要素名を取得したい」
「valueOfメソッドをオーバーライドしたいけどどうすればいいの?」
といった方はこの記事必見です!
この記事を読むことでvalueOfメソッドの意味と使い方をわかりやすく学ぶことができます!
なお、Javaの記事については、こちらにまとめています。
enumについて
まず本記事の本題に入る前にenumがどんなものかを軽くおさらいしておきましょう!
次のコードを見て下さい。
protected enum Fruit { Orange, Apple, Melon }; public static void main(String[] args) { Fruit fruit_type = Fruit.Orange; }
このコード自体は特に何かをするものではありませんがmainメソッドよりも前にenumというキーワードが付いたブロック(処理の塊)があります。
このブロックの中で定義されているOrangeやAppleは列挙子と呼ばれています。
enum自体の使い方の解説を深掘りすると本記事の目的に外れてしまうため避けておきますが、
なぜenumを使うのかというと簡単に言ってしまえば読みやすさ(可読性)を向上させることができるからです。
valueOfメソッドとは
早速本記事の主題であるenumでvalueOfメソッドを使うとどうなるかを解説していきたいと思います。
enumのvalueOfは引数で渡した文字列から列挙子名を取得するという意味があります。
どういうことかコードを見てみましょう。
protected enum Fruit { Orange, Apple, Melon; }; public static void main(String[] args) { if(Fruit.Orange == Fruit.valueOf("Orange")) { System.out.printf("一緒です。"); } }
実行結果
一緒です。
valueOfメソッドの引数に「Orange」という文字列を渡しています。
このOrangeを渡してFruitの列挙子にOrangeが定義されていればFruit.Orangeが戻り値として返ってくるというしくみになっています。
valueOfメソッドのオーバーライド
結論から言ってしまえば・・・
結論から言ってしまえば、valueOfメソッドをオーバーライドすることはできません。
実際、オーバーライドしようとするとエラーが発生します。
error: method valueOf(String) is already defined in enum XXX
オーバーライドはできませんがJavaのEnumクラスはメソッドを定義することができます。
今回はEnumの値を指定することで列挙子名を返してくれる処理を自作してみましょう。
コンストラクタ付きEnum
まず処理を自作する前にコンストラクタ付きEnumについて解説しておく必要性があります。
Enumの列挙子には変数のように値をもたせることが出来ます。
例えばこんな感じです。
public enum Fruit { Orange("Ehime"), Apple("Aomori"), Melon("Ibaraki"); private final String name; Fruit(String name) { this.name = name; } }
先程のコードとは違いOrangeやAppleの後に括弧がつくようになりました。
この括弧内のダブルクォーテーションで囲まれている文字列が値になります。
そしてその後に色々と処理が書いてありますが、値を保持しておくための変数を用意してコンストラクタが呼ばれた際に定義したプロパティnameに引数を代入しています。
このコンストラクタの処理がないとエラーがでて動かなくなるため注意が必要です。
値を保持しておくために必要なものだと考えて下さい。
Enum内にメソッドを定義する
前項の知識を前提として今度はメソッドを追加してみます。
では次のコードを見てみましょう。
public enum Fruit { Orange("Ehime"), Apple("Aomori"), Melon("Ibaraki"); private final String name; Fruit(String name) { this.name = name; } String getFruitName() { return this.name; } public static Fruit getTypeByValue(String str) { for(Fruit v : values()) { if(v.getFruitName().equals(str)) { return v; } } throw new IllegalArgumentException("undefined : " + str); } } public static void main(String[] args) { Fruit fruit = Fruit.getTypeByValue("Ibaraki"); System.out.printf("%s", fruit.toString()); }
まず先程のEnumと違うのはgetFruitNameというメソッドが追加されたことです。
さらにgetTypeByValueメソッドが追加されました。
これらは自作のメソッドです。
getTypeByValue内ではEnumに備わっているvaluesメソッドを使い値の一覧を取得しつつ拡張for文でループ処理を行います。
その処理の中身はひとつずつの列挙子名と引数strの値が一緒ならその列挙子を返すという処理になっています。
もし見つからない場合はIllegalArgumentException例外が発生するようになっています。
mainメソッド内で実際に使う際の例が書いてありますね。Ibarakiと引数に指定することでFruit.Melonが戻り値となります。
valueOfメソッドの例外
valueOfメソッドの利用時にもし存在しない列挙子の名称を指定した場合、IllegalArgumentException例外が発生します。
例えばこのような形のコードを書いた場合です。
protected enum Fruit { Orange, Apple, Melon; }; public static void main(String[] args) { Fruit fruit = Fruit.valueOf("WaterMelon"); }
IllegalArgumentException例外が発生した場合はvalueOfの引数を間違えていないかよく確認して見直す必要があります。
Enumについてもっと詳しく!
Enumについてもっと詳しく知りたい方は必見です!
まとめ
いかがでしょうか。
今回の記事ではvalueOfを使うことで列挙子を取得することができました。
もしEnumクラスのvalueOfの使い方を忘れてしまったらぜひこの記事を思い出して下さい!