Soru Java değerinin string değeriyle aranması


Sadece bir enum var diyelim

public enum Blah {
    A, B, C, D
}

ve örneğin bir dizenin enum değerini bulmak istiyorum. "A" hangi olurdu Blah.A. Bunu nasıl yapmak mümkün olabilir?

Mi Enum.valueOf() ihtiyacım olan yöntem? Eğer öyleyse, bunu nasıl kullanırdım?


1593
2018-03-02 22:56


Menşei




Cevaplar:


Evet, Blah.valueOf("A") sana vereceğim Blah.A.

Adın bir kesin dava dahil olmak üzere, maç: Blah.valueOf("a") ve Blah.valueOf("A ") her ikisi de bir atmak IllegalArgumentException.

Statik yöntemler valueOf() ve values() derleme zamanında oluşturulur ve kaynak kodunda görünmez. Gerçi Javadoc’ta gözüküyorlar; Örneğin, Dialog.ModalityType her iki yöntemi de gösterir.


1858
2018-03-02 22:57



Referans için, Blah.valueOf("A") yöntem harfe duyarlı ve yabancı boşlukları tolere etmez, bu nedenle aşağıda @ JoséMi tarafından önerilen alternatif çözüm. - Brett
@Michael Myers, Bu cevap şimdiye kadar en çok oyu aldığı için, bir enum ve String değerinin tam olarak aynı olması için iyi bir uygulama olduğunu anlamalı mıyım? - Kevin Meredith
@KevinMeredith: Eğer demek istiyorsan toString() değmez, hayır demezdim. name() geçersiz kılmadığınız sürece, enum sabitinin gerçek tanımlanmış adını alırsınız. - Michael Myers♦
Tam olarak ne demek "derleme zamanında oluşturulur ve kaynak kodunda görünmez." ? - treesAreEverywhere
@treesAreEverywhere Daha spesifik olarak, bu yöntemler oluşturulan (veya sentezlenen) derleyici tarafından. Gerçek enum Blah {...}tanım kendi beyan etmeyi denememeli values ne de valuesOf. Asla "sınıf" üye değişkeni beyan etmemiş olsanız bile "AnyTypeName.class" yazabilirsiniz. derleyici her şeyi sadece iş yapar. (Bu cevap 3 ay sonra sizin için yararlı olmayabilir, ama ne olur ne olmaz.) - Ti Strga


Metin, numaralandırma ile aynı değilse, başka bir çözüm:

public enum Blah {
  A("text1"),
  B("text2"),
  C("text3"),
  D("text4");

  private String text;

  Blah(String text) {
    this.text = text;
  }

  public String getText() {
    return this.text;
  }

  public static Blah fromString(String text) {
    for (Blah b : Blah.values()) {
      if (b.text.equalsIgnoreCase(text)) {
        return b;
      }
    }
    return null;
  }
}

711
2018-06-03 10:57



throw new IllegalArgumentException("No constant with text " + text + " found") daha iyi olurdu return null. - whiskeysierra
@whiskeysierra Jon Skeet buna katılmayacaktı. stackoverflow.com/questions/1167982/... - Sanghyun Lee
@Sangdol Could sen Bize null döndürme neden daha iyi olduğunu aydınlatmak? - whiskeysierra
@Sangdol genellikle, SUN - oops - Oracle'ın aynı durumda ne yaptığını kontrol etmek için iyi bir şeydir. Ve benzeri Enum.valueOf () gösteriliyor IS Bu durumda bir istisna atmak için en iyi uygulama. Çünkü bu olağanüstü bir durumdur. "Performans optimizasyonu" okunamayan kod yazmak için kötü bir bahane ;-) - raudi
Ayrıca, "okunabilir" ;-) yapmak için @Nullable ek açıklamasını da kullanabilirsiniz. - JoséMi


İşte kullandığım şık bir yardımcı program:

/**
 * A common method for all enums since they can't have another base class
 * @param <T> Enum type
 * @param c enum type. All enums must be all caps.
 * @param string case insensitive
 * @return corresponding enum, or null
 */
public static <T extends Enum<T>> T getEnumFromString(Class<T> c, String string) {
    if( c != null && string != null ) {
        try {
            return Enum.valueOf(c, string.trim().toUpperCase());
        } catch(IllegalArgumentException ex) {
        }
    }
    return null;
}

Sonra enum sınıfımda genellikle bazı yazarak kaydetmek için bu var:

public static MyEnum fromString(String name) {
    return getEnumFromString(MyEnum.class, name);
}

Enemleriniz tüm kapaklar değilse, sadece Enum.valueOf hat.

Çok kötü kullanamam T.class için Enum.valueOf gibi T silinir.


98
2017-11-12 15:52



O boş catch bloğu gerçekten beni deli ediyor, üzgünüm. - whiskeysierra
@LazloBonin: İstisnalar istisnai koşullar içindir, kontrol akışı için değildir. Kendine bir kopyasını al Etkili Java. - Martin Schröder
Kullanmak istediğiniz Java API'sı bir istisna atarsa ​​ve kodunuzun birini atmasını istemiyorsanız, bu gibi bir istisnayı yuttarabilir veya mantığı sıfırdan yeniden yazabilir, böylece ilk etapta istisna atılmaz. İstisnai yutmak genellikle daha az kötülüktür. - Nate C-K
Korkunç! Her zaman, her zaman Onları ele alabileceğiniz istisnaları yakalayın. Yukarıdaki örnek mükemmel bir örnektir nasıl yapılmaz. Niye ya? Yani NULL döndürür ve arayan NULL a karşı kontrol etmek veya bir NPE atmak zorundadır. Eğer arayan durumun nasıl ele alınacağını bilirse, bir denemeyi denemek biraz daha şık görünebilir. FAKAT eğer başaramazsa tekrar null ve arayanın arayanını geçmesi gerekiyor tekrar NULL vb. - raudi
Yukarıdaki çözüme karşı adil olmak için, gerçekten, IllegalArgumentException'ı atmak ve programınızın akışını kırmak yerine null döndürmeniz gereken durumları kullanır, örneğin, bir web hizmeti şeması ve bir veritabanı şeması arasında envanteri eşleme -birine. Ancak, catch bloğunun asla boş bırakılmaması gerektiğine katılıyorum. İzleme amacıyla log.warn veya bir şey gibi bir kod koyun. - Adrian M


Davanıza da dikkat etmelisiniz. Açıklamama izin ver Blah.valueOf("A") çalışır, ama Blah.valueOf("a") çalışmayacak. Sonra tekrardan Blah.valueOf("a".toUpperCase(Locale.ENGLISH)) çalışırdı.

Düzenle
değişmiş toUpperCase için toUpperCase(Locale.ENGLISH) dayalı tc. yorum Yap ve java dokümanlar

edit2 Android üzerinde kullanmalısınız Locale.US, gibi Sulai dikkat çekiyor.


66
2018-05-09 16:33



Varsayılan yerel ayardan çekinmeyin! - tc.
Dışarıda Android kullanıcıları için şunu belirtmek isterim Android belgeleri kullanımını açıkça teşvik ediyor Locale.US Makine tarafından okunabilir giriş / çıkış için. - sulai
Büyük harf farklı yerlerde farklı mıdır? - Holloway
@Trengot Evet. - João Portela
@Trengot Evet, maalesef. Türkiye iyi bir örnek. Bunu, Java'nın varsayılan varsayılan karakter kümeleriyle (varsayılan olarak Unicode yerine Windows'daki Latince varsayılan) ele almasıyla birleştirin ve bir karakter kümesini veya yerel ayarı kabul eden varsayılan yöntemlerin sürümünü kullanmak neredeyse her zaman güvensiz olduğunu göreceksiniz. Neredeyse her zaman onları açıkça tanımlamalısınız. - Stijn de Witt


Joshua Bloch'dan deseni kullan, Etkili Java:

(kısalık için basitleştirilmiş)

enum MyEnum {
  ENUM_1("A"),
  ENUM_2("B");

  private String name;

  private static final Map<String,MyEnum> ENUM_MAP;

  MyEnum (String name) {
    this.name = name;
  }

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

  // Build an immutable map of String name to enum pairs.
  // Any Map impl can be used.

  static {
    Map<String,MyEnum> map = new ConcurrentHashMap<String,MyEnum>();
    for (MyEnum instance : MyEnum.values()) {
      map.put(instance.getName(),instance);
    }
    ENUM_MAP = Collections.unmodifiableMap(map);
  }

  public static MyEnum get (String name) {
    return ENUM_MAP.get(name);
  }
}

Ayrıca bakınız:

Enum ve örneklerin Haritalarını kullanan Oracle Java Örneği

Bir Enum türünde statik blokların yürütme sırası

Java enum'unu String değerinden nasıl arayabilirim?


38
2018-06-15 16:37



Joshua Bloch söyledi eğer o zaman bu gitmek için tek yoldur :-). Her zaman burada aşağı inmek zorunda olduğum utanç verici. - dermoritz
Bu, Java 8'de yapabileceğiniz gibi daha da basittir:Stream.of(MyEnum.values()).collect(toMap(Enum::name, identity())) Ayrıca, özellikle Enum, seri hale getirilebilir verilerle ilişkilendirilirse, Sonar'a bir uyum sağlamadan kasayı kontrol etmenizi sağladığından, toString () (kurucu aracılığıyla iletilir) ve adın yerine kullanılması önerilir. - Novaterata
Java 8 kesinlikle bu forumda bir sürü (daha iyi) cevap verebilir. Kuyruğa (Sonar) sahip olmanın köpek (uygulama kodu) olmasına rağmen emin değilim. - Darrell Teague
Eğer bir yere koyacaksan unmodifiableMap neyse, o zaman bir ConcurrentHashMap. Sadece kullan HashMap. (Guava'nın varsa ImmutableMap o zaman bunun yerine bunu tavsiye ederim!) - Daniel Pryden
Google'ın ImmutableMap'i kesinlikle daha iyi (gerçek anlamda değişmez) bir uygulamadır, ancak tek çekirdekli Java çözümünü göstermek ve String harita arama kutusuna odaklanmak için sadece core-Java sınıfları kullanıldı. Genel olarak, ConcurrentHashMap'in eşzamanlı modifikasyonun göz önüne alınması gerektiğinde HashMap'e karşı genel performans profili (ekleme, çıkarma, değiştirme) ve sadeliğe karşı HashMap üzerinden neredeyse her zaman tercih edildiğini bulduk. - Darrell Teague


İşte herhangi bir Enum için yapabileceğiniz ve büyük / küçük harfe duyarlı olmayan bir yöntem.

/** 
 * Finds the value of the given enumeration by name, case-insensitive. 
 * Throws an IllegalArgumentException if no match is found.  
 **/
public static <T extends Enum<T>> T valueOfIgnoreCase(
        Class<T> enumeration, String name) {

    for (T enumValue : enumeration.getEnumConstants()) {
        if (enumValue.name().equalsIgnoreCase(name)) {
            return enumValue;
        }
    }

    throw new IllegalArgumentException(String.format(
        "There is no value with name '%s' in Enum %s",
        name, enumeration.getName()
    ));
}

34
2017-12-01 21:53



Bu varyasyon doğru şekilde yapıyor: equalsIgnoreCase gitmenin yolu. +1 - Stijn de Witt


kullanma Blah.valueOf(string) en iyisi ama kullanabilirsiniz Enum.valueOf(Blah.class, string) de.


28
2018-05-09 17:23



Büyük / küçük harfe duyarlı, yardım etmiyor! - Murtaza Kanchwala
@MurtazaKanchwala Yorumunuzu açıklayabilir misiniz? Ne yapmaya çalışıyorsun? - Peter Lawrey
Merhaba @PeterLawrey, Enum'u bir public public Enum ObjectType {PERSON ("Kişi") public String parametresinden getirmeyi deniyordum. ObjectType (String parameterName) {this.parameterName = parameterName; } public String getParameterName () {return this.parameterName; } public static ObjectType fromString (String parameterName) {if (parameterName! = null) {for (ObjectType nesne türü: ObjectType.values ​​()) {if (parameterName.equalsIgnoreCase (objType.parameterName)) {return objType; }}} dönüş null; }} - Murtaza Kanchwala


Kendi programınızı yazmak istemiyorsanız Google’ı kullanın  kütüphane:

Enums.getIfPresent(Blah.class, "A")

Yerleşik java fonksiyonundan farklı olarak, A'nın Blah'da olup olmadığını kontrol edersiniz ve bir istisna alamaz.


22
2018-04-02 20:12



hüzünlü bölüm, bu bir google Opsiyonel ve java opsiyonel değil - javaProgrammer


Buna ihtiyacınız olabilir:

public enum ObjectType {
    PERSON("Person");

    public String parameterName;

    ObjectType(String parameterName) {
        this.parameterName = parameterName;
    }

    public String getParameterName() {
        return this.parameterName;
    }

    //From String method will return you the Enum for the provided input string
    public static ObjectType fromString(String parameterName) {
        if (parameterName != null) {
            for (ObjectType objType : ObjectType.values()) {
                if (parameterName.equalsIgnoreCase(objType.parameterName)) {
                    return objType;
                }
            }
        }
        return null;
    }
}

Bir Daha Ekleme:

   public static String fromEnumName(String parameterName) {
        if (parameterName != null) {
            for (DQJ objType : DQJ.values()) {
                if (parameterName.equalsIgnoreCase(objType.name())) {
                    return objType.parameterName;
                }
            }
        }
        return null;
    }

Bu, Değeri Dizili bir Enum Adına döndürecektir. Örneğin, fromEnumName içinde "PERSON" yazarsanız, size Enum Değeri'ni döndürürsünüz, yani "Kişi"


13
2017-07-02 11:54