Java numaralandırmasında valueof () ve toString () geçersiz kıl


122

Benim içindeki değerler, enumiçlerinde boşluk olması gereken kelimelerdir, ancak numaralandırmaların değerlerinde boşluk olamaz, bu yüzden hepsi bir araya toplanmıştır. Söylediğim toString()yerlere bu boşlukları eklemek için geçersiz kılmak istiyorum .

Ayrıca valueOf(), boşlukları eklediğim aynı dizede kullandığımda numaralandırmanın doğru numaralandırmasını sağlamasını istiyorum .

Örneğin:

public enum RandomEnum
{
     StartHere,
     StopHere
}

Çağrı toString()üzerine RandomEnumkimin değerdir StartHeredöner dize "Start Here". valueof()Aynı string ( "Start Here") üzerinde yapılan çağrı , enum değerini döndürür StartHere.

Bunu nasıl yapabilirim?


2
Daha fazla yorum / yanıt almak için "Java" etiketini ekleyin.
Java42

Yanıtlar:


197

Bu kodu deneyebilirsiniz. valueOfYöntemi geçersiz kılamayacağınız için getEnum, ihtiyacınız olan değeri döndüren özel bir yöntem ( aşağıdaki örnek kodda) tanımlamanız ve bunun yerine istemcinizi bu yöntemi kullanacak şekilde değiştirmeniz gerekir.

public enum RandomEnum {

    StartHere("Start Here"),
    StopHere("Stop Here");

    private String value;

    RandomEnum(String value) {
        this.value = value;
    }

    public String getValue() {
        return value;
    }

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

    public static RandomEnum getEnum(String value) {
        for(RandomEnum v : values())
            if(v.getValue().equalsIgnoreCase(value)) return v;
        throw new IllegalArgumentException();
    }
}

4
Aşağıdakileri yaparsanız getEnum kısaltılabilir: v.getValue (). equals (value); boş kontrol atlanabilir.
rtcarlson

Ayrıca tembel bir şekilde bir harita oluşturabilir ve yeniden kullanabilirsiniz, ancak onu oluştururken iş parçacığı açma sorunlarına dikkat edin.
Maarten Bodewes

11
getValue () için valueOf () yönteminin çağrılmasını değiştiremeyeceğiniz senaryolarda çalışmaz, örneğin
sabit

Enumlar Java'da sabitlenene kadar @Bat'ın daha uygun ve OO dostu bir çözümü vardır. isim () nihai olmamalıdır.
Andrew T Finnell

for yerine valueOf (RandomEnum.class, value) kullanabilirsiniz;
Wojtek

22

Bunu dene ama her yerde işe yarayacağından emin değilim :)

public enum MyEnum {
    A("Start There"),
    B("Start Here");

    MyEnum(String name) {
        try {
            Field fieldName = getClass().getSuperclass().getDeclaredField("name");
            fieldName.setAccessible(true);
            fieldName.set(this, name);
            fieldName.setAccessible(false);
        } catch (Exception e) {}
    }
}

18
Neden bu tür şeylerin kötü göründüğü tek kişi benim? Demek istediğim, gerçekten harika görünüyor, ancak bu kodu okuyan bağlamı olmayan biri büyük olasılıkla "WTF?" Gibi olacaktır.
Nicolas Guillaume

11
@NicolasGu Guillaume Bu, eğer uygulanırsa, neden orada olduğunu ve programcının hangi sorunu çözmeye çalıştığını açıklayan bir yoruma çaresizce ihtiyaç duyacak türden bir koddur. :-)
Ti Strga

9
Bu OutOfMemory veya başka bir şey
İstisnayı

2
Bu berbat bir fikir. En önemlisi, hiçbir gösterge veya düzeltme olmaksızın sessiz hata olasılığıdır. Ayrıca artık koddaki "isim" değeri ve sembolik değer (örneğin A, B) farklıdır. Akıllı olduğun için +2. -200 çok zeki olduğu için. Bunun bir kod incelemesini onaylamamın bir yolu yok.
pedorro

1
@pedorro Bu, yaptığınız kadar korkunç görünmüyor. Java komitesinin yaptığı her şeyin, Müjde'nin bunu bir Kod İncelemesinde geçireceği gibi alınmaması gerektiğini anlayan herkes. İsim () geçersiz kılınamadığından, tüm Enum yardımcı program yöntemlerini yeniden yazmak ve sonra sürdürmek zorunda kalmak son derece kötüdür. İstisnayı yakalamak ve onu yutmak yerine, bir RuntimeException atılmalıdır ve sonra bu iyi olur.
Andrew T Finnell

14

Sabitleri numaralandırmak için Dizeleri eşleyen numaralandırmanızda statik bir Harita kullanabilirsiniz. Bunu bir 'getEnum' statik yönteminde kullanın. Bu, String değerinden bir tane almak istediğiniz her seferde numaralandırmalar arasında yineleme ihtiyacını atlar.

public enum RandomEnum {

    StartHere("Start Here"),
    StopHere("Stop Here");

    private final String strVal;
    private RandomEnum(String strVal) {
        this.strVal = strVal;
    }

    public static RandomEnum getEnum(String strVal) {
        if(!strValMap.containsKey(strVal)) {
            throw new IllegalArgumentException("Unknown String Value: " + strVal);
        }
        return strValMap.get(strVal);
    }

    private static final Map<String, RandomEnum> strValMap;
    static {
        final Map<String, RandomEnum> tmpMap = Maps.newHashMap();
        for(final RandomEnum en : RandomEnum.values()) {
            tmpMap.put(en.strVal, en);
        }
        strValMap = ImmutableMap.copyOf(tmpMap);
    }

    @Override
    public String toString() {
        return strVal;
    }
}

Sadece haritanın statik başlatılmasının, enum sabitlerinin bildiriminin altında gerçekleştiğinden emin olun.

BTW - bu 'ImmutableMap' türü Google guava API'sindendir ve bu gibi durumlarda kesinlikle tavsiye ederim.


DÜZENLEME - Yorum başına:

  1. Bu çözüm, atanan her dize değerinin benzersiz olduğunu ve boş olmadığını varsayar. Numaralamayı oluşturan kişinin bunu kontrol edebileceği ve dizenin benzersiz ve boş olmayan enum değerine karşılık geldiği göz önüne alındığında, bu güvenli bir kısıtlama gibi görünür.
  2. Soruda sorulduğu gibi 'toSTring ()' yöntemini ekledim

1
Bu cevapla ilgili birkaç olumsuz oy aldım - bu cevabın neden kötü olduğunu açıklamak isteyen var mı? Sadece insanların ne düşündüğünü merak ediyorum.
pedorro

Bu, aynı 'değere' sahip veya hiç 'değere' sahip olmayan birden fazla enum sabitine sahip senaryo için başarısız olacaktır (yani RestartHere("replay"), ReplayHere("replay")PauseHere, WaitHereprivate RandomEnum() { this.strVal = null; }
enum'un

1
+ ImmutableMap :: copyOf oluşturmak için bir MutableMap oluşturmak yerine ImmutableMap.Builder kullanmalısınız.
Bryan Correll

Bu ilginç görünüyor, ancak numaralandırma yalnızca birkaç farklı değere sahipse, bunları yinelemek uzun sürmeyecektir. Muhtemelen yalnızca numaralandırmanın çok fazla değeri varsa buna değer.
Ben Thurley

13

Java 8 uygulamasına ne dersiniz? (null, varsayılan Enum'unuzla değiştirilebilir)

public static RandomEnum getEnum(String value) {
    List<RandomEnum> list = Arrays.asList(RandomEnum.values());
    return list.stream().filter(m -> m.value.equals(value)).findAny().orElse(null);
}

Veya şunu kullanabilirsiniz:

...findAny().orElseThrow(NotFoundException::new);

2

Çalışmak için valueOf ("Buradan Başlayın") alacağınızı sanmıyorum. Ama boşluklara gelince ... aşağıdakileri deneyin ...

static private enum RandomEnum {
    R("Start There"), 
    G("Start Here"); 
    String value;
    RandomEnum(String s) {
        value = s;
    }
}

System.out.println(RandomEnum.G.value);
System.out.println(RandomEnum.valueOf("G").value);

Start Here
Start Here

2

Aşağıdaki, valueOf () 'a güzel bir genel alternatiftir

public static RandomEnum getEnum(String value) {
  for (RandomEnum re : RandomEnum.values()) {
    if (re.description.compareTo(value) == 0) {
      return re;
    }
  }
  throw new IllegalArgumentException("Invalid RandomEnum value: " + value);
}

Dizelerin kullanımı compareTo()daha zarif equals()mi?
Betlista

Zarafet bir sorun değil - bunun .equals()iyi çalışacağına katılıyorum . ==İstersen kullanabilirsin . (Olmama için iyi bir neden, sıralamayı bir sınıfla değiştirmemenizdir.)
istisna

3
@exception ASLA Dize karşılaştırmaları için == KULLANMAYIN çünkü ihtiyacınız olan şey içerik eşitliği kontrolü iken nesne eşitliği kontrolü yapacaktır ve bunun için String sınıfının equals () yöntemini kullanın.
sactiw

2

Hala numaranıza bunu uygulamak için bir seçeneğiniz var:

public static <T extends Enum<T>> T valueOf(Class<T> enumType, String name){...}
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.