Cara terbaik untuk membuat enum string?

364

Apa cara terbaik untuk memiliki enum tipe mewakili serangkaian string?

Saya mencoba ini:

enum Strings{
   STRING_ONE("ONE"), STRING_TWO("TWO")
}

Bagaimana saya bisa menggunakannya sebagai Strings?

Dori
sumber

Jawaban:

605

Saya tidak tahu apa yang ingin Anda lakukan, tetapi ini adalah cara saya menerjemahkan kode contoh Anda ....

package test;

/**
 * @author The Elite Gentleman
 *
 */
public enum Strings {
    STRING_ONE("ONE"),
    STRING_TWO("TWO")
    ;

    private final String text;

    /**
     * @param text
     */
    Strings(final String text) {
        this.text = text;
    }

    /* (non-Javadoc)
     * @see java.lang.Enum#toString()
     */
    @Override
    public String toString() {
        return text;
    }
}

Atau, Anda dapat membuat metode pengambil untuk text .

Sekarang Anda bisa melakukannya Strings.STRING_ONE.toString();

Buhake Sindi
sumber
3
Saya tidak tahu apakah ini merupakan persyaratan kompiler, tetapi private String textharus final.
Jonathan
7
@ Tomás Narros Ya, Anda masih dapat menetapkannya di konstruktor, selama Anda tidak memberikan nilai saat Anda mendeklarasikannya final.
Jonathan
28
@The Elite Gentleman Akan menjadi buruk jika nilai konstanta enum berubah selama runtime, jadi bahkan jika tidak diperlukan, finalakan lebih baik.
Jonathan
8
Jangan lupa bahwa Enums tidak dapat dibangun dengan newkonstruktor private. Pada dasarnya, pembuatan objek dilarang dan finaltidak benar-benar diperlukan dalam kasus ini.
Buhake Sindi
6
@ BuhakeSindi: itu benar, tetapi secara tidak sengaja seseorang mungkin cenderung untuk menempatkan setText(String)pada enum dan itu dapat melepaskan neraka :) finaljenis dokumen maksud Anda bahwa itu adalah konstan dengan dukungan kompiler. Jika Anda menggunakan Stringkonstanta, Anda tidak akan menyatakannya public static String, bukan?
TWiStErRob
104

Nilai String Khusus untuk Enum

dari http://javahowto.blogspot.com/2006/10/custom-string-values-for-enum.html

Nilai string default untuk java enum adalah nilai nominalnya, atau nama elemen. Namun, Anda dapat menyesuaikan nilai string dengan menimpa metode toString (). Sebagai contoh,

public enum MyType {
  ONE {
      public String toString() {
          return "this is one";
      }
  },

  TWO {
      public String toString() {
          return "this is two";
      }
  }
}

Menjalankan kode tes berikut akan menghasilkan ini:

public class EnumTest {
  public static void main(String[] args) {
      System.out.println(MyType.ONE);
      System.out.println(MyType.TWO);
  }
}


this is one
this is two
vaichidrewar
sumber
16
Ini bukan cara yang efisien untuk melakukan ini. Ini menciptakan kelas khusus baru untuk setiap nilai dalam enumerasi. Dalam contoh di atas, Anda akan melihat yang berikut ini di bindirektori: EnumTest $ MyType.class EnumTest $ MyType $ 1.class EnumTest $ MyType $ 2.class yang akan bertambah sangat cepat. Terbaik untuk melakukannya sebagai jawaban yang diharapkan, dengan memberikan nilai pada konstruktor enum. Saya sebenarnya tidak setuju dengan penggantian toString(); Saya percaya lebih baik menggunakan pengambil yang eksplisit seperti getKey()karena mengganti toString()mungkin tidak terduga oleh pengguna enum lainnya.
Matt Quigley
sepenuhnya setuju dengan @MattQuigley. Hal tersebut mendorong pengguna untuk menggunakan toString untuk hal-hal yang seharusnya tidak digunakan. Jika Anda membutuhkan label, Anda lebih suka menambahkan atribut label
Sebastien Lorber
Juga, tidak ada cara untuk pergi sebaliknya (dari string ke objek enum) yang mungkin akan diperlukan di beberapa titik.
Adrian Smith
menimpa toString tidak memengaruhi valueOf (), bukan?
Dmitriusan
69

Gunakan name()metodenya:

public class Main {
    public static void main(String[] args) throws Exception {
        System.out.println(Strings.ONE.name());
    }
}

enum Strings {
    ONE, TWO, THREE
}

hasil panen ONE.

Bart Kiers
sumber
17
Ya, tetapi Strings.STRING_ONE.name()menghasilkan "STRING_ONE", bukan "ONE". Ini bukan jawaban yang bagus. Anda tidak dapat memiliki String yang tidak akan menjadi pengidentifikasi Java yang valid, dll.
Mark Peters
2
@Ark, benar, tidak bisa menangani karakter apa pun. Jika OP hanya menginginkan satu karakter, solusi ini lebih mudah daripada saran The Elite Gentleman. Tapi memang: jika rentang karakter melebihi yang dimiliki pengenal Java yang valid, ini adalah no-go. Poin yang bagus.
Bart Kiers
Sangat masuk akal untuk memiliki konvensi penamaan internal untuk enum yang berbeda dari apa yang ingin ditampilkan dengan toString () (terutama jika pengguna melihat output), jadi saya tidak berpikir ini seperti apa OP itu mencari.
Michael McGowan
17
Hasil dari name()dapat dipengaruhi oleh program obfuscator. Saya mengalami masalah yang sama beberapa waktu lalu. Misalnya, dengan Proguard Anda harus mengatasi ini. Lihat Memproses Kelas Enumerasi
noisecapella
Ini luar biasa. Bekerja dengan nilai-nilai seperti: var_name, var_superlong_but_not_toooooo_long_name, genap dll (tanpa titik tripple)
19

Entah nama enum sama dengan string yang Anda inginkan atau, secara umum, Anda bisa mengaitkan atribut arbitrer dengan nilai enum Anda:

enum Strings {
   STRING_ONE("ONE"), STRING_TWO("TWO");
   private final String stringValue;
   Strings(final String s) { stringValue = s; }
   public String toString() { return stringValue; }
   // further methods, attributes, etc.
}

Sangat penting untuk memiliki konstanta di bagian atas, dan metode / atribut di bagian bawah.

Adrian Smith
sumber
Dan juga memiliki konstruktor pribadi .
Buhake Sindi
1
enum konstruktor bersifat pribadi secara default dan tidak memerlukan pengubah akses. Tapi itu poin bagus tentang pengubah akses secara umum, saya telah memperbarui kode saya untuk menambahkannya ke atribut dan accessor.
Adrian Smith
15

Bergantung pada apa yang Anda maksud dengan "gunakan mereka sebagai String", Anda mungkin tidak ingin menggunakan enum di sini. Dalam kebanyakan kasus, solusi yang diusulkan oleh Elite Gentleman akan memungkinkan Anda untuk menggunakannya melalui metode toString mereka, misalnya dalam System.out.println(STRING_ONE)atau String s = "Hello "+STRING_TWO, tetapi ketika Anda benar-benar membutuhkan String (mis. STRING_ONE.toLowerCase()), Anda mungkin lebih suka mendefinisikannya sebagai konstanta:

public interface Strings{
  public static final String STRING_ONE = "ONE";
  public static final String STRING_TWO = "TWO";      
}
hd42
sumber
5
sebenarnya ini yang saya coba hindari ...!
Dori
Sebenarnya, jika mereka juga menginginkan toLowerCase()solusi saya, mereka bisa pergi Strings.STRING_TWO.toString().toLowerCase().
Buhake Sindi
Tentu, tetapi itu tidak menggunakan mereka sebagai string seperti yang saya menafsirkannya. Karena Rrackham tampaknya tidak memerlukan penggunaan itu, ia tentu saja harus menggunakan solusi enum yang diusulkan.
HD42
6
Anda tidak boleh menggunakan interfacedi tempat finalkelas dengan privatekonstruktor. Ini adalah praktik yang tidak dianjurkan.
Aleks N.
1
@mils, solusi menggunakan enum bekerja dengan baik dalam sebuah saklar. Saya akan menyarankan solusi ini hanya jika Strings diperlukan secara langsung.
HD42
8

Anda dapat menggunakannya untuk string Enum

public enum EnumTest {
    NAME_ONE("Name 1"),
    NAME_TWO("Name 2");

    private final String name;

    /**
     * @param name
     */
    private EnumTest(final String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

Dan panggilan dari metode utama

public class Test {
    public static void main (String args[]){
        System.out.println(EnumTest.NAME_ONE.getName());
        System.out.println(EnumTest.NAME_TWO.getName());
    }
}
Shohel Rana
sumber
5

Jika Anda tidak ingin menggunakan konstruktor , dan Anda ingin memiliki nama khusus untuk metode ini, coba ini:

public enum MyType {
  ONE {
      public String getDescription() {
          return "this is one";
      }
  },    
  TWO {
      public String getDescription() {
          return "this is two";
      }
  };

  public abstract String getDescription();
}

Saya menduga ini adalah solusi tercepat . Tidak perlu menggunakan variabel final .

Adam111p
sumber
tetapi dengan yang ini Anda masih harus memanggil getDescription () di mana orang yang meminta ingin memanggil ONE atau mengaksesnya sebagai konstanta.
kinsley kajiva
Saya lebih memilih ini. Apa yang akan terjadi jika perlu menerima lebih banyak informasi? Dengan solusi ini tambahkan saja metode abstrak yang dilindungi dan lewati. Terlebih lagi tidak perlu mengganti metode toString (). Bersih dan dapat diterima sebagai jawaban terbaik.
Arundev
0

Dapatkan dan atur dengan nilai default.

public enum Status {

    STATUS_A("Status A"),  STATUS_B("Status B"),

    private String status;

    Status(String status) {
        this.status = status;
    }

    public String getStatus() {
        return status;
    }
}
Pravin
sumber