Numaralandırma değerlerini Dize değişmezleri olarak kullanma


389

Bir Enum'da String değişmezleri olarak depolanan değerleri kullanmanın en iyi yolu nedir? Örneğin:

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

Daha sonra Mode.mode1dize temsilini döndürmek için kullanabilirsiniz mode1. Aramaya devam etmeden Mode.mode1.toString().

Yanıtlar:


646

Yapamazsın. Bence burada DÖRT seçenek var. Dördü de biraz farklı bir yaklaşımla çözüm sunuyor ...

Birinci Seçenek: kullanmak yerleşik name()bir enum üzerinde. Herhangi bir özel adlandırma formatına ihtiyacınız yoksa bu gayet iyi.

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

İkinci Seçenek: daha fazla kontrol istiyorsanız numaralandırmalarınıza geçersiz kılma özellikleri ekleyin

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

Üçüncü Seçenek: numaralandırmalar yerine statik finaller kullanın:

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

Dördüncü Seçenek: arayüzlerde her alan genel, statik ve son olarak bulunur:

public interface Modes {

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

46
Bu cevap aslında yanlış: arayabileceğiniz gibi .name()Bkz: stackoverflow.com/a/6667365/887836
Alex

3
@ kato2 doğru değil. .Name () yöntemi derleyici tarafından otomatik olarak oluşturulur
Sean Patrick Floyd

10
JavaDoc: String java.lang.Enum.name () Bu numaralandırma sabitinin adını, tam olarak numaralandırma bildiriminde bildirildiği gibi döndürür. ToString yöntemi daha kullanıcı dostu bir ad döndürebileceğinden, çoğu programcı bu tercih yerine toString yöntemini kullanmalıdır. Bu yöntem, öncelikle doğruluğun, sürümden sürüme değişmeyecek olan tam adı almaya bağlı olduğu özel durumlarda kullanılmak üzere tasarlanmıştır. Döndürür: bu numaralandırma sabitinin adı
SuperRetro

@Ryan Stewart'ın daha kötüsü daha az kod ve daha az kod gerektirir == daha az hata şansı
Eric

4
Sabitleri tutmak için arabirimleri kullanmayın: Etkili Java (3. sürüm) "yalnızca türleri tanımlamak için arabirimleri kullanmanızı" önerir (madde 22).
Olivier Grégoire

481

Her numaralandırmanın hem name () hem de valueOf (String) yöntemi vardır. Birincisi, numaralandırmanın dize adını döndürür ve ikincisi, adı dize olan enum değerini verir. Aradığın gibi mi?

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

Ayrıca Enum'un kendisinde statik bir valueOf (Class, String) vardır, böylece

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

50
BU CEVAP olmalıdır! A ("A") gibi bir şey kullanmak hata kaynağı olabilir ve anlamsız bir iştir!
Firzen

12
@Firzen, dize değerinin boşluk veya kısa çizgi içermesine izin verilirse (durum böyle değildir) some-really-long-string.
ceving

@ceving Soru boşluklar ve kısa çizgilerle ilgili olarak iyi ifade edilmemiştir. Sorular tirelenmiş bir örneği gösterir, ancak tirelenmiş değerleri kullanarak bir Enum'un nasıl oluşturulacağını sormaz. Bunun yerine, soru, tirelenmiş değerleri belirtmeden toString öğesini çağırmak zorunda kalmadan String değerinin nasıl alınacağını sorar. Bununla birlikte, Enum değerlerinin hala Java adlandırma kurallarına uyması gerektiğini ve bu tür karakterler gerekliyse kabul edilen cevapta belirtilen bir şeyi kullanması gerektiğini belirtmek gerekirse, bu daha iyi bir yanıt olabileceğini söyledi.
Hazok

Dize dönüşüm sağlamak için yöntem ile birlikte kullanan mkyong için bir bağlantı eklemek istedim . valueOf(String)toUpperCase(Locale)
Bilinmiyor Id

2
Birçok insanın Enum.name () yerine özellik yaklaşımını tercih etmesinin nedeni, Enum.name () etrafında bulunan mantığın sonsuza kadar değer adlarının merhametinde olmasıdır. Kod, gelecekteki her değişiklikte, önceki mantık Enum değer kümesindeki değişiklikleri bozacağından, etrafta dolaşmak önemsiz bir soruna dönüşebilir. ToString () yaklaşımının geçersiz kılınması ve kullanılması, geliştiricinin, çoğaltma, geçerli olmayan değişken adı karakterleri vb. Dahil olmak üzere kullanım değerleri üzerinde daha fazla kontrole sahip olmasına izin verir.
bölünmez

79

toString()Her numaralandırma değeri için yöntemi geçersiz kılabilirsiniz .

Misal:

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

}

Kullanımı:

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
Bunu severim. Hiçbir neden vb her tür, bir dizi olsun, böyle bütün değerlerin listesini almak gibi başka işlevlere sahip bir sınıf olarak bir enum kullanmamaya
diegosasw

8
Çirkin ve yeniden kullanılamaz. Ülke için yapıcı olarak bir dize değeri sağlamak ve sonra numaralandırma için toString () yöntemini geçersiz kılmak çok daha iyi.
greg7gkb

4
Bu, oldukça büyük bir numaralandırmanız olduğunda ve yalnızca bir veya iki üye için yazdırılan şeyleri geçersiz kılmak istediğinizde iyi bir tekniktir.
Donal Fellows

3
Bu hiç ölçeklenmiyor. Bunu yapma.
sebnukem

1
Bu bana mantıklı geliyor
hanzolo

35

Benny Neugebauer'in bahsettiği gibi, toString () üzerine yazabilirsiniz. Ancak bunun yerine her numaralandırma alanı için toString üzerine yazma ben daha böyle bir şey gibi:

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

Ayrıca, tüm alanları almak, tümünü yazdırmak vb. İçin statik bir yöntem ekleyebilirsiniz. Her Numaralandırma öğesiyle ilişkili dizeyi almak için getValue'yu çağırmanız yeterlidir.



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

değeri numaradan dize olarak almak istediğiniz her yerde aşağıdaki gibi bir arama yapabilirsiniz.

Modes.MODE1.getvalue();

Bu "Mode1" bir dize olarak döndürür.


6

Sen kullanabilirsiniz Mode.mode1.name()ancak sık sık bunu yapmak gerekmez.

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

6
+ Operatörünün numaradan () değil, numaradan toString () öğesini çağırdığını belirtmek gerekir. Ve toString (), adından başka bir şey döndürmek için geçersiz kılınabilir (arzu
edilmese

1
Her ikisi de name()ve toString()geçersiz kılınabilir, ancak umarım bu gerçekleşiyorsa için kodu okumaktan açıkça anlaşılacaktır enum.
Peter Lawrey

9
No. name () son şeklindedir ve her zaman numaralandırma bildirgesinde bildirildiği gibi numaralandırmanın adını döndürür.
JB Nizet

1
@JB Nizet, haklısın. name()olduğunu final. Beni doğruladığınız için teşekkür ederim. :)
Peter Lawrey

6

Bildiğim kadarıyla, adı almanın tek yolu

Mode.mode1.name();

Bununla birlikte, gerçekten bu şekilde ihtiyacınız varsa, şunları yapabilirsiniz:

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

    private String name;       

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

1
Ancak bu durumda, Mode.mode1hala tipte değildir String.
Larry

Ah doğru. Amacı yenecek bir getName () yöntemine ihtiyacınız vardır, bu nedenle hayır, bunu yapamazsınız.
Jake Roussel

"name" kötü alan adı, standart enum alanıdır.
Wooff

6

Numaralarım için her birinin 1 String ile tahsis edilmesini gerçekten sevmiyorum. Bu şekilde bir toString () yöntemi numaralandırmalara uygulamak.

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
Erişilemeyen kod olması gerektiği için null döndürmek yerine bir çalışma zamanı istisnası atmak daha iyi olur mu?
kiralar

Bu returngereksizdir çünkü tüm numaralandırmalarla numaralandırmaları sonlandırır.
Danon

5

Sadece şunu kullanabilirsiniz:

""+ Modes.mode1

Ben bu konuda% 100 emin değilim ama benim kadarıyla bu döküm gerekli değildir, değil mi? Boş bir dizeyi başka bir değişkenle birleştirmek otomatik olarak bir dönüşüm çağrısında bulunmalı mı yoksa bu kuralın istisnaları var mı?
Bilinmeyen Kimlik

1
Haklısın, doğru sürüm olmalı "" + Modes.mode1. Cevabı düzelttim
Buddy

EB'nin yanıtı python deyimini anımsatarak da faydalanır ''.join()
antropik android

5

senin sorunun için benim çözüm!

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'nin sorunu 4 yıl önce çözülmüş gibi görünüyor, ancak StackOverflow'a hoş geldiniz :)
TDG

1
Teşekkürler, sadece benim gibi birine yardım etmek, eski sorunlara daha objektif cevaplar aramak için :)
Renan Galdino da Silva

3

Enum sadece biraz özel bir sınıftır. Numaralandırmalar ek alanları depolayabilir, yöntemleri uygulayabilir vb.

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

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

Şimdi diyebilirsiniz:

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

ve çıktıya bakın: 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
Sorunu nasıl çözeceğini açıklayabilir misiniz?
Phani

bu satırı kullanarak bu numaralandırmayı istediğiniz yere çağırabilirsiniz: int id = 1; String dayName = Days.getDay (id); , buraya geç id. "Salı" olan bir kimlik için Açıklama döndürecektir

2

Bu yöntem aşağıdakilerle çalışmalıdır 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();

Yazdırılacak:

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

Numaralandırma dizesi sabitleri için bu tasarım çoğu durumda çalışır.


0

birçok denemeden sonra bu çözümle geldim

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

Bunu deneyebilirsiniz:

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

i bu tür hata önlemek için daha kolay bulundu:

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

    String str;

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

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

ancak - bir log / println'de bir String kullanmanız gerektiğinde veya java toString () yöntemini otomatik olarak derlediğinde, ancak bunun gibi bir kod satırında çalışabilir ->

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

bunun yerine yukarıda belirtildiği gibi, enum'u genişletmeniz ve .name() bu gibi durumlarda kullanmanız gerekecektir :

intent.putExtra(Modes.mode1.name() ,shareElement.getMode()); 
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.