🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

列挙型

データ型の一種で、要素・メンバなど名前のある値や、型の列挙子によって構成されます。

Q&A

解決済

3回答

6450閲覧

Java : enumの重複列挙定数について

Rai_Feit

総合スコア7

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

列挙型

データ型の一種で、要素・メンバなど名前のある値や、型の列挙子によって構成されます。

0グッド

0クリップ

投稿2019/10/18 06:50

編集2019/10/18 08:02

前提・実現したいこと

Java初心者です. 初投稿で, 見苦しい点もあると思いますがよろしくお願いします.

Javaでマジックナンバを防ぐために, enumを実装したいのですが,
その際に異なる列挙子に重複する定数を扱う方法はありますか?

追記: 具体的には, コンストラクタで同じフィールド変数に書き込んでいるので, 引数から列挙子を逆引きするときに(parseメソッド)目的の列挙子をうまく呼べないという事象が発生している.

マジックナンバを単にstatic final などで保持するよりも, 型の安全性があると伺ったので試用しましたが,
同じ値の定数に対してenumは有効ではないのでしょうか?

該当のソースコード(やりたいことのイメージ)

画面入力から受け取った値をStringで保管し, switchで画面遷移させたいとき

java

1enum Type 2{ 3 メニュー1("1"), 4 メニュー2("2"), 5 りんご("1"),    // ←このような例 6 ぶどう("2"); 7 戻る("e"), 8 9 // getter, setter , コンストラクタ, etc..(省略) 10 11 // String to Object 12 public static Type parse(String stat) 13 { 14 for (Type st : values()) 15 { 16 if (st.field.equals(stat)) 17 { 18 return st; 19 } 20 } 21 throw new RuntimeException("Unknown type code:" + stat); 22 } 23} 24 // 画面入力用 ↓ 25static Scanner sc = new Scanner(System.in); 26 27public static String scanner() 28 { 29 String in = sc.nextLine(); 30 return in; 31 } 32public static void closeScanner() 33 { 34 sc.close(); 35 } 36

クライアント側

メニュー画面

java

1while(true){ 2 try 3 { 4 switch (Type.parse(scanner())) 5 { 6 case メニュー1: 7 //画面遷移先呼び出し処理 (省略) 8 case メニュー2: 9         //同上 10 case 戻る: 11   closeScanner(); 12   System.out.print("終了しました"); 13   System.exit(0); 14     default: 15     break; 16 } 17 } 18 catch (RuntimeException e) 19 { 20 System.err.println("入力は不正です.もう一度入力してください"); 21 } 22}

画面遷移先

java

1// メニュー1内とする 2try 3{ 4 switch (Type.parse(scanner())) 5 { 6 case りんご: 7      // りんごに対する処理 8 case ぶどう: 9 case 戻る: 10  default: 11 break; 12   } 13} 14catch (RuntimeException e) 15{ 16 System.err.println("入力は不正です.もう一度入力してください"); 17 controllInquryDisplay(); 18}

###イメージ

サンプルメニュー
1) メニュー1
2) メニュー2
該当の項目を入力してください
ユーザ入力 : 1

メニュー1

  1. りんご
  2. ぶどう

該当の項目を入力してください
ユーザ入力 : 1

上記のような動作イメージです
現在は, メニュー1で1を入力すると(当然ですが) case りんご: に入りません
######候補案

  1. enumを複数用意する

ex) enum Type1{}, enum Type2{}, ...
2. 素直に static final なメンバ変数を使う

など思いつきましたが, 少し迷走してる気もします.

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

maisumakun

2019/10/18 07:00

えっと、「1」を入力した場合、「メニュー1」と「りんご」のどちらが得られるのが正解なのでしょうか。
Rai_Feit

2019/10/18 07:16

ありがとうございます。動作イメージ追加しました。 どちらも正なんですが、場合によって振る舞いを変えたいです。(そもそもその実装にenumは適していない?)
S_kawa

2019/10/18 08:41

1つのクラスに全てのコード値をまとめる是非さておき(私は反対です) 出来るできないで言えば今回のケースはparseメソッドを複数用意すれば実現できますね。 泥臭い実装になりますが…ifに&条件付けるなりSwitchするなり、その時取りうるものだけに限定してreturnするよう仕向ければいいでしょう。 例) if (st.field.equals(stat) && (st.eaquls(りんご) || st.eaquls(ぶどう)))
Rai_Feit

2019/10/18 14:50

ありがとうございます。 1つのクラスに全てのコード値をまとめる是非さておき(私は反対です) 初学者の私にとって, 特に ↑ このような意見非常に有り難いです.
guest

回答3

0

ベストアンサー

マジックナンバを防ぐために, enumを実装したい

とされているのに, なぜ階層構造まで enum で表現することになるのでしょう.
enum をマジックナンバーに戻したとして, 結果的に階層構造を表現するには情報が足りないことになるはずです.

コードは全て動作確認していません

enum で階層構造を表現しつつでしたら以下のようになるかと思います.

java

1 enum Type { 2 Any(null), //階層に関係無い項目("戻る")のparent用 3 メニュー1("1"), 4 メニュー2("2"), 5 りんご(メニュー1, "1"), // ←このような例 6 ぶどう(メニュー1, "2"), 7 戻る(Any, "e"); 8 9 Type parent; 10 String field; 11 Type(String field) { 12 this(null, field); 13 } 14 Type(Type parent, String field) { 15 this.parent = parent; 16 this.field = field; 17 } 18 // String to Object 19 public static Type parse(Type parent, String stat) { 20 for (Type st : values()) { 21 if ((st.parent == Any || st.parent == parent) && st.field.equals(stat)) { 22 return st; 23 } 24 } 25 throw new RuntimeException("Unknown type code:" + stat); 26 } 27 }

メニュー1を選択後にりんご/ぶどうを選択する場合は次のように書けると思います.

java

1 switch (Type.parse(Type.メニュー1, scanner())) { 2 case りんご: 3 //りんごに対する処理 4 case ぶどう: 5 case 戻る: 6 default: 7 break; 8 }

投稿2019/10/18 08:38

jimbe

総合スコア13201

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Rai_Feit

2019/10/18 14:44

そんな実装方法があるとは...勉強になりました.. 私の疑問に対する的確な回答と, 綺麗なコード(解答例), ありがとうございます。一番欲しい回答をくださったので, BAに選ばせていただきました!
guest

0

異なる列挙子に重複する定数

列挙子に同じ値は設定できるようです。
下記・・・「フィールド変数とコンストラクタの定義」を参考に
Enum(列挙型)の使い方総まとめ
この場合は、違う列挙子に違う値を設定していますが、同じものも出来ると思います。

投稿2019/10/18 07:40

cateye

総合スコア6851

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

cateye

2019/10/18 07:43

質問を読み返して、外してる気がした^^;・・・思い違いなら無視して下さい。
Rai_Feit

2019/10/18 07:50

貴重な解答ありがとうございます。 伝わりにくい粗末な文で申し訳ありません。 回答について 定義はできることに間違いないですが, コンストラクタで同じフィールドに書き込んでいることになるので, 引数からの逆引きで目的の "りんご"がうまく呼べない点を解消したいという内容です.
guest

0

上記のような動作イメージです

別なリストにあるものであれば、同じenumに入れるべきでないことは間違いありません。

投稿2019/10/18 07:17

maisumakun

総合スコア145967

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Rai_Feit

2019/10/18 07:23

ありがとうございます. では, このようなケースで enum を使うとき 候補案 1 の別の enum に入れるのが有効であり, 同じ enum に入れるような使い方はしないし, enum は そのように 使うべきものではないということで間違いないでしょうか.
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問