Menggunakan nilai Enum sebagai String literal


389

Apa cara terbaik untuk menggunakan nilai yang disimpan dalam Enum sebagai String literal? Sebagai contoh:

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

Lalu nanti saya bisa gunakan Mode.mode1untuk mengembalikan representasi string sebagai mode1. Tanpa harus terus menelepon Mode.mode1.toString().

Jawaban:


646

Kamu tidak bisa Saya pikir Anda memiliki EMPAT opsi di sini. Keempatnya menawarkan solusi tetapi dengan pendekatan yang sedikit berbeda ...

Opsi Satu: gunakan built-in name()pada enum. Ini sangat baik jika Anda tidak memerlukan format penamaan khusus.

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

Opsi Dua: tambahkan properti override ke enum Anda jika Anda ingin lebih banyak kontrol

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;
    }
}

Opsi Tiga: gunakan final statis daripada enum:

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() { }
}

Opsi Empat: antarmuka memiliki setiap bidang publik, statis dan final:

public interface Modes {

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

46
Jawaban ini sebenarnya salah: seperti yang Anda sebut .name()See: stackoverflow.com/a/6667365/887836
Alex

3
@ kato2 tidak benar. Metode .name () dibuat secara otomatis oleh kompiler
Sean Patrick Floyd

10
JavaDoc: String java.lang.Enum.name () Mengembalikan nama konstanta enum ini, persis seperti yang dinyatakan dalam deklarasi enumnya. Sebagian besar programmer harus menggunakan metode toString sebagai preferensi untuk yang satu ini, karena metode toString dapat mengembalikan nama yang lebih ramah pengguna. Metode ini dirancang terutama untuk digunakan dalam situasi khusus di mana kebenaran tergantung pada mendapatkan nama yang tepat, yang tidak akan berbeda dari rilis ke rilis. Pengembalian: nama konstanta enum ini
SuperRetro

Awser dari @Ryan Stewart membutuhkan lebih sedikit kode dan lebih sedikit kode == lebih sedikit peluang bug
Eric

4
Jangan gunakan antarmuka untuk memegang konstanta: Java yang Efektif (edisi ke-3) merekomendasikan untuk "menggunakan antarmuka hanya untuk mendefinisikan tipe" (item 22).
Olivier Grégoire

481

Setiap enum memiliki nama () dan metode valueOf (String). Yang pertama mengembalikan nama string dari enum, dan yang terakhir memberikan nilai enum yang namanya adalah string. Apakah ini yang Anda cari?

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

Ada juga valueOf (Class, String) statis pada Enum itu sendiri, jadi Anda juga bisa menggunakannya

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

50
INI harus menjadi JAWABAN! Menggunakan sesuatu seperti A ("A") dapat menjadi sumber kesalahan dan ini merupakan pekerjaan ekstra yang tidak masuk akal!
Firzen

12
@ Firzen tidak jika nilai string diizinkan mengandung spasi atau tanda hubung, yang merupakan kasus di some-really-long-string.
ceving

@ceving Pertanyaan ini tidak diutarakan dengan baik sehubungan dengan spasi dan tanda hubung. Pertanyaan menunjukkan contoh ditulis dgn tanda penghubung, tetapi tidak bertanya bagaimana membuat Enum menggunakan nilai ditulis dgn tanda penghubung. Alih-alih, pertanyaannya adalah bagaimana mendapatkan nilai String tanpa harus memanggil toString tanpa menentukan nilai hyphenated adalah persyaratan. Yang mengatakan, saya pikir ini bisa menjadi jawaban yang lebih baik jika diubah untuk menyebutkan bahwa nilai-nilai Enum masih harus mengikuti aturan penamaan Jawa dan akan perlu menggunakan sesuatu yang disebutkan dalam jawaban yang diterima jika karakter tersebut diperlukan.
Hazok

Saya ingin menambahkan tautan ke mkyong yang menggunakan valueOf(String)metode ini dalam kombinasi dengan toUpperCase(Locale)untuk memastikan konversi String.
Id Tidak Diketahui

2
Alasan banyak orang lebih suka pendekatan properti daripada Enum.name () adalah bahwa logika berbasis di sekitar Enum.name () kemudian selamanya tergantung pada belas kasihan nama nilai. Jika setiap perubahan kode di masa depan ini bisa berubah menjadi masalah non sepele untuk disiasati karena semua logika sebelumnya akan memecah perubahan pada set nilai Enum. Mengganti dan menggunakan pendekatan toString () memungkinkan pengembang untuk memiliki kontrol yang lebih besar atas nilai-nilai yang digunakan termasuk duplikasi, karakter nama variabel tidak valid dll. Jangan lupa juga menimpa valueOf ().
tidak dapat dipisahkan

79

Anda bisa mengganti toString()metode untuk setiap nilai enum.

Contoh:

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";
    }
  }

}

Pemakaian:

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
Saya suka ini. Tidak ada alasan untuk tidak menggunakan enum sebagai kelas dengan fungsionalitas lebih lanjut seperti mendapatkan daftar semua nilai, mendapatkan string dari setiap jenis, dll.
diegosasw

8
Jelek dan tidak bisa digunakan kembali. Jauh lebih baik untuk memberikan nilai string sebagai konstruktor untuk Negara dan kemudian mengganti metode toString () untuk enum.
greg7gkb

4
Ini adalah teknik yang baik ketika Anda memiliki enumerasi yang cukup besar dan hanya ingin menimpa apa yang dicetak untuk satu atau dua anggota.
Donal Fellows

3
Ini tidak berskala sama sekali. Jangan lakukan ini.
sebnukem

1
Ini masuk akal bagi saya
hanzolo

35

Seperti yang dikatakan Benny Neugebauer, Anda bisa menimpa toString (). Namun alih-alih menimpa toString untuk setiap bidang enum, saya lebih suka sesuatu seperti ini:

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();
    }
}

Anda juga bisa menambahkan metode statis untuk mengambil semua bidang, untuk mencetak semuanya, dll. Cukup panggil getValue untuk mendapatkan string yang terkait dengan setiap item 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;
 } 
}

Anda dapat membuat panggilan seperti di bawah ini di mana pun Anda ingin mendapatkan nilai sebagai string dari enum.

Modes.MODE1.getvalue();

Ini akan mengembalikan "Mode1" sebagai String.


6

Anda dapat menggunakan Mode.mode1.name()namun Anda sering tidak perlu melakukan ini.

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

6
Perlu dicatat bahwa operator + akan memanggil toString () pada enum, dan bukan nama (). Dan toString () dapat diganti untuk mengembalikan sesuatu selain namanya (bahkan jika itu tidak diinginkan)
JB Nizet

1
Keduanya name()dan toString()bisa diganti, tetapi mudah-mudahan ini akan menjadi jelas dari membaca kode untuk enumjika ini terjadi.
Peter Lawrey

9
Nama () adalah final, dan selalu mengembalikan nama enum sebagaimana dinyatakan dalam deklarasi enumnya.
JB Nizet

1
@ JP Nizet, Anda benar. name()adalah final. Terima kasih telah mengoreksi saya. :)
Peter Lawrey

6

Sejauh yang saya tahu, satu-satunya cara untuk mendapatkan nama itu adalah

Mode.mode1.name();

Namun, jika Anda benar-benar membutuhkannya, Anda dapat melakukan:

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

    private String name;       

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

1
Tetapi dalam hal ini, Mode.mode1masih bukan tipe String.
Larry

Oh benar Anda memerlukan metode getName (), yang mengalahkan tujuannya, jadi tidak, Anda tidak bisa melakukan ini.
Jake Roussel

"nama" adalah nama bidang yang buruk, itu adalah bidang standar enum.
Wooff

6

Untuk enum saya, saya tidak suka memikirkan mereka dialokasikan dengan masing-masing 1 String. Ini adalah bagaimana saya menerapkan metode toString () pada enum.

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
Melempar pengecualian runtime akan lebih baik daripada mengembalikan nol karena harus berupa kode yang tidak terjangkau?
sewa

Itu returnberlebihan, karena menyalakan enum dengan semua enum berakhir.
Danon

5

Anda cukup menggunakan:

""+ Modes.mode1

Saya tidak 100% yakin akan hal ini, tetapi sejauh pengetahuan saya, para pemeran ini tidak perlu, bukan? Menggabungkan string kosong dengan variabel lain harus secara otomatis meminta konversi, atau adakah pengecualian untuk aturan ini?
Id Tidak Diketahui

1
Anda benar, versi yang benar seharusnya "" + Modes.mode1. Saya memperbaiki jawabannya
Sobat

Jawaban EB juga diuntungkan dengan mengingatkan pada idiom python ''.join()
anthropic android

5

solusi saya untuk masalah Anda!

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!");

    }
}

Sepertinya masalah OP telah diselesaikan 4 tahun yang lalu, tetapi selamat datang di StackOverflow :)
TDG

1
Terima kasih, hanya untuk membantu orang seperti saya, mencari jawaban yang lebih objektif untuk masalah lama :)
Renan Galdino da Silva

3

Enum hanya sedikit kelas khusus. Enum dapat menyimpan bidang tambahan, menerapkan metode, dll. Misalnya

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

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

Sekarang Anda bisa mengatakan:

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

dan lihat output: 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
Bisakah Anda menjelaskan tentang cara menyelesaikan masalah?
Phani

Anda dapat memanggil enum ini di mana saja dengan menggunakan baris ini: int id = 1; String dayName = Days.getDay (id); , lewat sini id. itu akan mengembalikan Deskripsi untuk id itu yaitu "Selasa"

2

Metode ini harus bekerja dengan 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();

Itu akan mencetak:

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

Desain ini untuk konstanta string enum bekerja di sebagian besar kasus.


0

setelah banyak mencoba saya datang dengan solusi ini

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

Anda dapat mencoba ini:

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

saya menemukan ini lebih mudah untuk mencegah kesalahan tipe:

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

    String str;

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

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

Namun - ini dapat bekerja ketika Anda perlu menggunakan String pada log / println atau setiap kali java mengkompilasi metode toString () secara otomatis, tetapi pada baris kode seperti ini ->

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

alih-alih seperti yang disebutkan di atas, Anda masih harus memperpanjang enum dan menggunakannya .name() dalam kasus-kasus seperti ini:

intent.putExtra(Modes.mode1.name() ,shareElement.getMode()); 
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.