Enum値を文字列リテラルとして使用する


389

Enumに格納されている値を文字列リテラルとして使用する最良の方法は何ですか?例えば:

public enum Modes {
    some-really-long-string,
    mode1,
    mode2,
    mode3
}

その後Mode.mode1、文字列表現をとして返すために使用できますmode1。電話をかけ続ける必要はありませんMode.mode1.toString()

回答:


646

できません。ここには4つのオプションがあると思います。4つすべてがソリューションを提供しますが、アプローチは少し異なります...

オプション1: 列挙型で組み込みを使用しname()ます。特別なネーミングフォーマットが必要ない場合は、これで問題ありません。

    String name = Modes.mode1.name(); // Returns the name of this enum constant, exactly as declared in its enum declaration.

オプション2: 詳細な制御が必要な場合は、オーバーライドにプロパティを列挙に追加します

public enum Modes {
    mode1 ("Fancy Mode 1"),
    mode2 ("Fancy Mode 2"),
    mode3 ("Fancy Mode 3");

    private final String name;       

    private Modes(String s) {
        name = s;
    }

    public boolean equalsName(String otherName) {
        // (otherName == null) check is not needed because name.equals(null) returns false 
        return name.equals(otherName);
    }

    public String toString() {
       return this.name;
    }
}

オプション3: 列挙型の代わりに静的ファイナルを使用する:

public final class Modes {

    public static final String MODE_1 = "Fancy Mode 1";
    public static final String MODE_2 = "Fancy Mode 2";
    public static final String MODE_3 = "Fancy Mode 3";

    private Modes() { }
}

オプション4: インターフェースには、すべてのフィールドがpublic、static、finalがあります。

public interface Modes {

    String MODE_1 = "Fancy Mode 1";
    String MODE_2 = "Fancy Mode 2";
    String MODE_3 = "Fancy Mode 3";  
}

46
この答えは実際には間違っています.name():See を呼び出すことができます:stackoverflow.com/a/6667365/887836
Alex

3
@ kato2は正しくありません。.name()メソッドはコンパイラーによって自動的に作成されます
Sean Patrick Floyd

10
JavaDoc: String java.lang.Enum.name() この列挙型定数の名前を、その列挙型宣言で宣言されているとおりに返します。ほとんどのプログラマは、toStringメソッドがよりわかりやすい名前を返す可能性があるため、これよりもtoStringメソッドを使用する必要があります。このメソッドは、正確さが正確な名前の取得に依存する特殊な状況での使用を主な目的として設計されており、リリースごとに異なりません。戻り値:この列挙型定数の名前
SuperRetro 2017

@Ryan Stewartのawserは必要なコードとコードが少ない==バグの可能性が少ない
Eric

4
定数を保持するためにインターフェースを使用しない:効果的なJava(第3版)では、「型を定義するためにのみインターフェースを使用する」ことを推奨しています(アイテム22)。
OlivierGrégoire18年

481

すべての列挙型には、name()メソッドとvalueOf(String)メソッドの両方があります。前者は列挙型の文字列名を返し、後者は名前が文字列である列挙値を返します。これはあなたが探しているものに似ていますか?

String name = Modes.mode1.name();
Modes mode = Modes.valueOf(name);

Enum自体にも静的なvalueOf(Class、String)があるので、

Modes mode = Enum.valueOf(Modes.class, name);

50
これは答えになるはずです!A( "A")のようなものを使用すると、エラーの原因になる可能性があり、意味のない余分な作業になります。
Firzen、2014

12
@Firzenは、文字列値にスペースまたはハイフンを含めることが許可されている場合はそうではありませんsome-really-long-string
14年

@ceving質問はスペースやハイフンに関してはうまく表現されていません。質問はハイフン付きの例を示していますが、ハイフン付きの値を使用してEnumを作成する方法を尋ねていません。代わりに、ハイフン付きの値を指定せずにtoStringを呼び出さずにString値を取得する方法が必要です。とは言っても、Enumの値はJavaの命名規則に従う必要があり、そのような文字が必要な場合は、承認された回答に記載されているものを使用する必要があると述べるように修正された場合、これはより良い回答になると思います。
ハゾク2015年

文字列変換を確実にするためにと組み合わせてメソッドを使用するmkyongへのリンクを追加したいと思いました。valueOf(String)toUpperCase(Locale)
不明なID

2
多くの人がEnum.name()よりもプロパティアプローチを好む理由は、Enum.name()に基づいたロジックが値の名前のなすがままになることです。コードが将来すべての変更を行う場合、以前のすべてのロジックがEnum値セットへの変更を中断するため、回避するために重要な問題になる可能性があります。toString()アプローチをオーバーライドして使用すると、開発者は使用中の値をより詳細に制御できます。これには、重複、無効な変数名の文字などが含まれます。valueOf()もオーバーライドすることを忘れないでください。
分割

79

toString()各列挙値のメソッドをオーバーライドできます。

例:

public enum Country {

  DE {
    @Override
    public String toString() {
      return "Germany";
    }
  },
  IT {
    @Override
    public String toString() {
      return "Italy";
    }
  },
  US {
    @Override
    public String toString() {
      return "United States";
    }
  }

}

使用法:

public static void main(String[] args) {
  System.out.println(Country.DE); // Germany
  System.out.println(Country.IT); // Italy
  System.out.println(Country.US); // United States
}

2
私はこれが好き。すべての値のリストを取得する、各タイプの文字列を取得するなどの追加機能を備えたクラスとして列挙型を使用しない理由はありません
diegosasw

8
醜く、再利用できません。Countryのコンストラクターとして文字列値を指定し、列挙型のtoString()メソッドをオーバーライドする方がはるかに優れています。
greg7gkb 2015年

4
これは、列挙が非常に大きく、1つまたは2つのメンバーの場合に何が出力されるかをオーバーライドするだけの場合に適した手法です。
ドナルフェロー

3
これはまったくスケーリングしません。これを行わないでください。
sebnukem 2015年

1
これは私には理にかなっています
ハンゾロ2016

35

Benny Neugebauerが言及しているように、toString()を上書きできます。ただし、代わりに各列挙フィールドのtoStringを上書きするので、次のようなものがさらに好きです。

public enum Country{
    SPAIN("España"),
    ITALY("Italia"),
    PORTUGAL("Portugal");


    private String value;

    Country(final String value) {
        this.value = value;
    }

    public String getValue() {
        return value;
    }

    @Override
    public String toString() {
        return this.getValue();
    }
}

静的メソッドを追加して、すべてのフィールドを取得したり、すべてを印刷したりすることもできます。単にgetValueを呼び出して、各Enumアイテムに関連付けられた文字列を取得します。



21
public enum Modes {
  MODE1("Mode1"),
  MODE2("Mode2"),
  MODE3("Mode3");

 private String value;
 public String getValue() {
    return value;
   }
 private Modes(String value) {
  this.value = value;
 } 
}

enumから文字列として値を取得したい場所であればどこでも、以下のような呼び出しを行うことができます。

Modes.MODE1.getvalue();

これは「Mode1」を文字列として返します。


6

使用することはできますMode.mode1.name()が、頻繁に行う必要はありません。

Mode mode =
System.out.println("The mode is "+mode);

6
+演算子は、name()ではなく列挙型のtoString()を呼び出すことに注意してください。また、toString()をオーバーライドして、名前以外のものを返すこともできます(望ましくない場合でも)
JB Nizet

1
name()toString()は両方ともオーバーライドできますが、enumこれが発生している場合ののコードを読むことでこれが明確になることを願っています。
Peter Lawrey、2011

9
いいえ。name()は最終的なものであり、enum宣言で宣言されているenumの名前を常に返します。
JBニゼット2011

1
@JBニゼット、あなたは正しいです。name()ですfinal。訂正していただきありがとうございます。:)
ピーター・ローリー

6

私の知る限り、名前を取得する唯一の方法は

Mode.mode1.name();

ただし、この方法で本当に必要な場合は、次のようにすることができます。

public enum Modes {
    mode1 ("Mode1"),
    mode2 ("Mode2"),
    mode3 ("Mode3");

    private String name;       

    private Modes(String s) {
        name = s;
    }
}

1
しかし、この場合Mode.mode1はまだタイプではありませんString
ラリー

そうそう。getName()メソッドが必要ですが、これは目的に反するため、できません。
ジェイクルーセル

「name」は悪いフィールド名で、enumの標準フィールドです。
Wooff 2015

6

私の列挙型では、それぞれに1つの文字列が割り当てられているとは思いません。これは、列挙型にtoString()メソッドを実装する方法です。

enum Animal
{
    DOG, CAT, BIRD;
    public String toString(){
        switch (this) {
            case DOG: return "Dog";
            case CAT: return "Cat";
            case BIRD: return "Bird";
        }
        return null;
    }
}

1
ランタイム例外をスローすると、到達できないコードになるため、nullを返すよりも良いでしょうか?
2018年

returnすべての列挙型と列挙型のスイッチが終端されているので、冗長です。
Danon

5

あなたは単に使うことができます:

""+ Modes.mode1

私はこれについて100%確信はありませんが、私の知る限り、このキャストは必要ありませんか?空の文字列を別の変数と連結すると、自動的に変換が呼び出されますか、このルールに例外はありますか?
不明なID

1
そのとおり"" + Modes.mode1です。正しいバージョンはです。私は答えを修正しました
バディ

EBの答えはまた、Pythonのイディオムを彷彿とさせることによって利益を得る ''.join()
anthropicアンドロイド

5

あなたの問題に対する私の解決策!

import java.util.HashMap;
import java.util.Map;

public enum MapEnumSample {
    Mustang("One of the fastest cars in the world!"), 
    Mercedes("One of the most beautiful cars in the world!"), 
    Ferrari("Ferrari or Mercedes, which one is the best?");

    private final String description;
    private static Map<String, String> enumMap;

    private MapEnumSample(String description) {
        this.description = description;
    }

    public String getEnumValue() {
        return description;
    }

    public static String getEnumKey(String name) {
        if (enumMap == null) {
            initializeMap();
        }
        return enumMap.get(name);
    }

    private static Map<String, String> initializeMap() {
        enumMap = new HashMap<String, String>();
        for (MapEnumSample access : MapEnumSample.values()) {
            enumMap.put(access.getEnumValue(), access.toString());
        }
        return enumMap;
    }

    public static void main(String[] args) {

        // getting value from Description
        System.out.println(MapEnumSample.getEnumKey("One of the fastest cars in the world!"));

        // getting value from Constant
        System.out.println(MapEnumSample.Mustang.getEnumValue());

        System.out.println(MapEnumSample.getEnumKey("One of the most beautiful cars in the world!"));
        System.out.println(MapEnumSample.Mercedes.getEnumValue());

        // doesnt exist in Enum
        System.out.println("Mustang or Mercedes, which one is the best?");
        System.out.println(MapEnumSample.getEnumKey("Mustang or Mercedes, which one is the best?") == null ? "I don't know!" : "I believe that "
                + MapEnumSample.getEnumKey("Ferrari or Mustang, which one is the best?") + " is the best!.");

        // exists in Enum
        System.out.println("Ferrari or Mercedes, wich one is the best?");
        System.out.println(MapEnumSample.getEnumKey("Ferrari or Mercedes, which one is the best?") == null ? "I don't know!" : "I believe that "
                + MapEnumSample.getEnumKey("Ferrari or Mercedes, which one is the best?") + " is the best!");

    }
}

OPの問題は4年前に解決されたようですが、StackOverflowへようこそ:)
TDG

1
ありがとう、私のような人を助け、古い問題に対するより客観的な答えを探しています:)
Renan Galdino da Silva

3

Enumは少し特別なクラスです。列挙型は、追加のフィールドを格納したり、メソッドを実装したりできます。たとえば、

public enum Modes {
    mode1('a'),
    mode2('b'),
    mode3('c'),
    ;
    char c;

    private Modes(char c) {
        this.c = c;
    }
    public char character() {
        return c;
    }
}

今あなたは言うことができます:

System.out.println(Modes.mode1.character())

そして出力を見てください: a


3
package com.common.test;

public  enum Days {


    monday(1,"Monday"),tuesday(2,"Tuesday"),wednesday(3,"Wednesday"),
    thrusday(4,"Thrusday"),friday(5,"Friday"),saturday(6,"Saturday"),sunday(7,"Sunday");

    private int id;
    private String desc;


    Days(int id,String desc){
        this.id=id;
        this.desc=desc;
    }

    public static String getDay(int id){

        for (Days day : Days.values()) {
            if (day.getId() == id) {
                return day.getDesc();
            }
        }
        return null;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }



};

1
問題をどのように解決するかについて説明できますか?
Phani、2016年

次の行を使用して、この列挙型をどこでも呼び出すことができます。int id = 1; 文字列dayName = Days.getDay(id); 、ここにIDを渡します。「Tuesday」であるそのIDの説明を返します

2

このメソッドは次のいずれでも機能するはずenumです。

public enum MyEnum {
    VALUE1,
    VALUE2,
    VALUE3;

    public int getValue() {
        return this.ordinal();
    }

    public static DataType forValue(int value) {
        return values()[value];
    }

    public String toString() {
        return forValue(getValue()).name();
    }
}

2
public enum Environment
{
    PROD("https://prod.domain.com:1088/"),
    SIT("https://sit.domain.com:2019/"),
    CIT("https://cit.domain.com:8080/"),
    DEV("https://dev.domain.com:21323/");

    private String url;

    Environment(String envUrl) {
        this.url = envUrl;
    }

    public String getUrl() {
        return url;
    }
}

String prodUrl = Environment.PROD.getUrl();

印刷されます:

https://prod.domain.com:1088/

この列挙型文字列定数の設計は、ほとんどの場合に機能します。


0

多くの試みの後、私はこの解決策を思いついた

public static enum Operation {

    Addition, Subtraction, Multiplication, Division,;

    public String getUserFriendlyString() {
        if (this==Addition) {
            return " + ";
        } else if (this==Subtraction) {
            return " - ";
        } else if (this==Multiplication) {
            return " * ";
        } else if (this==Division) {
            return " / ";
        }
        return "undefined";
       }
}

0

あなたはこれを試すことができます:

public enum Modes {
    some-really-long-string,
    mode1,
    mode2,
    mode3;

    public String toString(){
        switch(this) {
            case some-really-long-string:
                return "some-really-long-string";
            case mode2:
                return "mode2";
            default: return "undefined";
        }
    }

}


0

私はこれがタイプエラーを防ぐのにもっと簡単だとわかりました:

public enum Modes {
    some-really-long-string,
    mode1,
    mode2,
    mode3;

    String str;

    Modes(){
        this.str = super.name();
    }

    @Override
    @NonNull
    public String toString() {
        return str;
    }

ただし、これは、log / printlnでStringを使用する必要があるとき、またはjavaがtoString()メソッドを自動的にコンパイルするときはいつでも機能しますが、次のようなコード行では機能します->

// sample method that require (string,value)
intent.putExtra(Modes.mode1 ,shareElement.getMode()); // java error
// first argument enum does not return value

代わりに、上記のように、列挙型を拡張して、次の.name() ような場合に使用する必要があります。

intent.putExtra(Modes.mode1.name() ,shareElement.getMode()); 
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.