मैं अपने स्ट्रिंग मूल्य से जावा एनम कैसे देख सकता हूं?


164

मैं इसके स्ट्रिंग मान (या संभवतः किसी अन्य मूल्य) से एक एनम देखना चाहता हूं। मैंने निम्नलिखित कोड आज़माया है, लेकिन यह इनिशियलाइज़र में स्टेटिक की अनुमति नहीं देता है। क्या कोई सरल तरीका है?

public enum Verbosity {

    BRIEF, NORMAL, FULL;

    private static Map<String, Verbosity> stringMap = new HashMap<String, Verbosity>();

    private Verbosity() {
        stringMap.put(this.toString(), this);
    }

    public static Verbosity getVerbosity(String key) {
        return stringMap.get(key);
    }
};

IIRC, जो एक NPE देता है क्योंकि स्थैतिक आरंभीकरण शीर्ष नीचे किया जाता है (यानी शीर्ष पर एनुम स्थिरांक का निर्माण किया जाता है इससे पहले कि यह stringMapआरंभीकरण के नीचे हो जाए )। सामान्य समाधान एक नेस्टेड वर्ग का उपयोग करना है।
टॉम हॉल्टिन -

इतनी तेज प्रतिक्रिया के लिए आप सभी का धन्यवाद। (एफडब्ल्यूआईडब्ल्यू मुझे इस समस्या के लिए सूर्य जावदोक बहुत उपयोगी नहीं लगा)।
peter.murray.rust

यह वास्तव में एक पुस्तकालय मुद्दे की तुलना में एक भाषा का मुद्दा है। हालाँकि, मुझे लगता है कि एपीआई डॉक्स जेएलएस (हालांकि शायद भाषा डिजाइनरों द्वारा नहीं) से अधिक पढ़े जाते हैं, इसलिए इस तरह की चीजों को शायद java.lang डॉक्स में अधिक प्रमुखता होनी चाहिए।
टॉम हॉल्टिन -

जवाबों:


241

valueOfप्रत्येक Enum के लिए स्वचालित रूप से बनाई गई विधि का उपयोग करें ।

Verbosity.valueOf("BRIEF") == Verbosity.BRIEF

मनमाने मूल्यों के साथ शुरू:

public static Verbosity findByAbbr(String abbr){
    for(Verbosity v : values()){
        if( v.abbr().equals(abbr)){
            return v;
        }
    }
    return null;
}

यदि आपका प्रोफाइलर आपको बताता है तो केवल बाद में मानचित्र कार्यान्वयन के लिए आगे बढ़ें।

मुझे पता है कि यह सभी मूल्यों पर ध्यान केंद्रित कर रहा है, लेकिन केवल 3 enum मानों के साथ यह शायद ही किसी अन्य प्रयास के लायक है, वास्तव में जब तक आपके पास बहुत सारे मूल्य नहीं हैं मैं एक मानचित्र के साथ परेशान नहीं करूंगा यह काफी तेजी से होगा।


धन्यवाद - और मैं केस रूपांतरण का उपयोग कर सकता हूं यदि मुझे पता है कि मूल्य अभी भी अलग हैं
peter.murray.rust

आप "v.abbr ()" के बजाय "v.abbr.equals ..." का उपयोग करने के बजाय कक्षा के सदस्य 'abbr' तक पहुँच प्राप्त कर सकते हैं।
Amio.io

7
इसके अलावा, मनमाने मूल्यों के लिए (दूसरा मामला) IllegalArgumentExceptionवापस लौटने के बजाय ( यानी जब कोई मैच नहीं मिला है) फेंकने पर विचार करें - यह Enum.valueOf(..)वैसे भी जेडीके करता है।
प्रीड्यू नीमरे

135

तुम पास हो। मनमाने मूल्यों के लिए, निम्न जैसा कुछ प्रयास करें:

public enum Day { 

    MONDAY("M"), TUESDAY("T"), WEDNESDAY("W"),
    THURSDAY("R"), FRIDAY("F"), SATURDAY("Sa"), SUNDAY("Su"), ;

    private final String abbreviation;

    // Reverse-lookup map for getting a day from an abbreviation
    private static final Map<String, Day> lookup = new HashMap<String, Day>();

    static {
        for (Day d : Day.values()) {
            lookup.put(d.getAbbreviation(), d);
        }
    }

    private Day(String abbreviation) {
        this.abbreviation = abbreviation;
    }

    public String getAbbreviation() {
        return abbreviation;
    }

    public static Day get(String abbreviation) {
        return lookup.get(abbreviation);
    }
}

4
क्लास लोडर मुद्दों के कारण यह विधि विश्वसनीय काम नहीं करेगी। मैं इसकी अनुशंसा नहीं करता हूं और मैंने इसे नियमित रूप से विफल होते देखा है क्योंकि लुकअप मैप एक्सेस होने से पहले तैयार नहीं है। आपको "लुकअप" को एनम के बाहर या किसी अन्य वर्ग में रखना होगा ताकि वह पहले लोड हो।
एडम जेंट

7
@ एडम गेंट: जेएलएस के नीचे एक लिंक है जहां यह सटीक निर्माण एक उदाहरण के रूप में प्रस्तुत किया गया है। यह कहता है कि स्थैतिक प्रारंभ ऊपर से नीचे तक होता है: docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#d5e12267
सेलेना

3
हां आधुनिक जावा जैसे जावा 8 ने मेमोरी मॉडल तय किया है। कहा जा रहा है कि अगर आप सर्कुलर रेफरेंस के कारण इनिशियलाइजेशन को एम्बेड करते हैं तो jrebel जैसे हॉट स्वैप एजेंट्स अभी भी गड़बड़ हो जाते हैं।
एडम जेंट

@ एडम गेंट: हम्म। मुझे हर दिन कुछ नया सीखना अच्छा लगता है। [चुपचाप बूटस्ट्रैप सिंगलेट्स के साथ मेरी दुश्मनी को दूर करने के लिए फिसल रहा है ...] क्षमा करें अगर यह एक बेवकूफ सवाल है, लेकिन क्या यह ज्यादातर स्थैतिक आरंभीकरण के साथ एक समस्या है?
सेलेना

मैंने कभी भी स्थैतिक कोड ब्लॉक के साथ मुद्दों को शुरू नहीं देखा है, लेकिन मैंने जावा में शुरू होने के बाद से केवल जावा 8 का उपयोग किया है, 2015 में। मैंने जेएमएच 1.22 का उपयोग करते हुए थोड़ा सा बेंचमार्क किया और एनमों HashMap<>को स्टोर करने के लिए उपयोग करना साबित हुआ। 40% से अधिक तेजी से एक लूप लूप से।
cbaldan

21

जावा 8 के साथ आप इस तरह से प्राप्त कर सकते हैं:

public static Verbosity findByAbbr(final String abbr){
    return Arrays.stream(values()).filter(value -> value.abbr().equals(abbr)).findFirst().orElse(null);
}

मैं लौटने के बजाय एक अपवाद फेंक दूंगा null। लेकिन यह उपयोग के मामले पर भी निर्भर करता है
अलेक्जेंडर

12

@ लाइल का जवाब खतरनाक है और मैंने देखा है कि यह विशेष रूप से काम नहीं करता है यदि आप एनम को एक स्थिर आंतरिक वर्ग बनाते हैं। इसके बजाय मैंने कुछ इस तरह का उपयोग किया है जो कि बूटस्ट्रैपिंगलिंग मैप्स को एनमों से पहले लोड करेगा।

इसे संपादित करना आधुनिक JVMs (JVM 1.6 या अधिक) के साथ कोई समस्या नहीं होनी चाहिए, लेकिन मुझे लगता है कि JRebel के साथ अभी भी समस्याएँ हैं, लेकिन मुझे इसे फिर से पढ़ने का मौका नहीं मिला है

मुझे पहले लोड करें:

   public final class BootstrapSingleton {

        // Reverse-lookup map for getting a day from an abbreviation
        public static final Map<String, Day> lookup = new HashMap<String, Day>();
   }

अब इसे एनम कंस्ट्रक्टर में लोड करें:

   public enum Day { 
        MONDAY("M"), TUESDAY("T"), WEDNESDAY("W"),
        THURSDAY("R"), FRIDAY("F"), SATURDAY("Sa"), SUNDAY("Su"), ;

        private final String abbreviation;

        private Day(String abbreviation) {
            this.abbreviation = abbreviation;
            BootstrapSingleton.lookup.put(abbreviation, this);
        }

        public String getAbbreviation() {
            return abbreviation;
        }

        public static Day get(String abbreviation) {
            return lookup.get(abbreviation);
        }
    }

यदि आपके पास एक आंतरिक एनम है तो आप बस एनम परिभाषा के ऊपर मैप को परिभाषित कर सकते हैं और यह (सिद्धांत में) पहले लोड होना चाहिए।


3
"खतरनाक" को परिभाषित करने की आवश्यकता है और एक आंतरिक वर्ग कार्यान्वयन क्यों मायने रखता है। यह एक टॉप-बॉटम स्टैटिक डेफिनिशन इश्यू से अधिक है, लेकिन इस सवाल के लिंक के साथ एक अन्य संबंधित उत्तर में वर्किंग कोड है जो एनुम उदाहरण पर एक स्टैटिक मैप का उपयोग करता है जो उपयोगकर्ता द्वारा परिभाषित मूल्य से "प्राप्त" विधि के साथ है। ईनम प्रकार। stackoverflow.com/questions/604424/lookup-enum-by-string-value
डेरेल टीग

2
@DarrellTeague मूल मुद्दा पुराने JVM (पूर्व 1.6) या अन्य JVM (IBMs) या हॉटकोड स्वैपर (JRebel) के कारण था। मुद्दा आधुनिक जेवीएम में नहीं होना चाहिए ताकि मैं अपना उत्तर हटा सकूं।
एडम जेंट

ध्यान दें कि वास्तव में कस्टम कंपाइलर कार्यान्वयन और रनटाइम ऑप्टिमाइज़ेशन के कारण यह संभव है ... ऑर्डर को पुनः वितरित किया जा सकता है, जिसके परिणामस्वरूप त्रुटि हो सकती है। हालाँकि, यह युक्ति का उल्लंघन प्रतीत होता है।
डेरेल टीग

7

और आप valueOf () का उपयोग नहीं कर सकते हैं ?

संपादित करें: Btw, आपको एक एनम में स्थिर {} का उपयोग करने से कुछ भी नहीं रोक रहा है।


या valueOfएनम वर्ग पर सिंथेटिक , इसलिए आपको एनम क्लास को निर्दिष्ट करने की आवश्यकता नहीं है Class
टॉम हॉल्टिन -

बेशक, यह सिर्फ एक जावाडॉक प्रविष्टि नहीं थी इसलिए इसे लिंक करना कठिन था।
फ्रेड्रिक

1
आप valueOf () का उपयोग कर सकते हैं, लेकिन नाम को इनकम डिक्लेरेशन में उस सेट से अनौपचारिक रूप से मेल खाना चाहिए। ऊपर दिए गए दो लुकअप तरीकों में से किसी को भी .equalsIgnoringCase () का उपयोग करने के लिए संशोधित किया जा सकता है और त्रुटि के लिए थोड़ी अधिक मजबूती है।

@ एलोनार्डो ट्रू। अगर इसमें मजबूती आती है या सिर्फ दोष-सहिष्णुता बहस का मुद्दा है। ज्यादातर मामलों में मैं कहूंगा कि यह बाद की बात है और उस मामले में इसे कहीं और संभालना बेहतर है और अभी भी Enum के valueOf () का उपयोग करें।
फ्रेड्रिक

4

मामले में यह दूसरों की मदद करता है, जो विकल्प मुझे पसंद है, जो यहां सूचीबद्ध नहीं है, अमरूद के मानचित्र की कार्यक्षमता का उपयोग करता है :

public enum Vebosity {
    BRIEF("BRIEF"),
    NORMAL("NORMAL"),
    FULL("FULL");

    private String value;
    private Verbosity(final String value) {
        this.value = value;
    }

    public String getValue() {
        return this.value;
    }

    private static ImmutableMap<String, Verbosity> reverseLookup = 
            Maps.uniqueIndex(Arrays.asList(Verbosity.values()), Verbosity::getValue);

    public static Verbosity fromString(final String id) {
        return reverseLookup.getOrDefault(id, NORMAL);
    }
}

डिफ़ॉल्ट के साथ आप उपयोग कर सकते हैं null, तो आप कर सकते हैं throw IllegalArgumentExceptionया अपने fromStringएक वापसी कर सकता है Optional, जो कुछ भी व्यवहार आप पसंद करते हैं।


3

जावा 8 के बाद से आप नक्शे को एक पंक्ति में और स्थिर ब्लॉक के बिना शुरू कर सकते हैं

private static Map<String, Verbosity> stringMap = Arrays.stream(values())
                 .collect(Collectors.toMap(Enum::toString, Function.identity()));

+1 धाराओं का उत्कृष्ट उपयोग, और पठनीयता का त्याग किए बिना बहुत संक्षिप्त! मैंने पहले भी इसका उपयोग नहीं देखा था Function.identity(), मुझे यह कहीं अधिक आकर्षक लगता है e -> e
मतसु Q।

0

शायद, इस पर एक नज़र डालें। मेरे लिए यह काम कर रहा है। इसका उद्देश्य 'RED' को '/ red_color' के साथ देखना है। एक की घोषणा करना static mapऔर enumइसे एस में लोड करना केवल एक बार कुछ प्रदर्शन लाभ लाएगा यदि enumएस कई हैं।

public class Mapper {

public enum Maps {

    COLOR_RED("/red_color", "RED");

    private final String code;
    private final String description;
    private static Map<String, String> mMap;

    private Maps(String code, String description) {
        this.code = code;
        this.description = description;
    }

    public String getCode() {
        return name();
    }

    public String getDescription() {
        return description;
    }

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

    public static String getColorName(String uri) {
        if (mMap == null) {
            initializeMapping();
        }
        if (mMap.containsKey(uri)) {
            return mMap.get(uri);
        }
        return null;
    }

    private static void initializeMapping() {
        mMap = new HashMap<String, String>();
        for (Maps s : Maps.values()) {
            mMap.put(s.code, s.description);
        }
    }
}
}

कृपया अपने कोप्सन में रखें।


-1

आप अपने Enum को निम्न कोड के रूप में परिभाषित कर सकते हैं:

public enum Verbosity 
{
   BRIEF, NORMAL, FULL, ACTION_NOT_VALID;
   private int value;

   public int getValue()
   {
     return this.value;
   } 

   public static final Verbosity getVerbosityByValue(int value)
   {
     for(Verbosity verbosity : Verbosity.values())
     {
        if(verbosity.getValue() == value)
            return verbosity ;
     }

     return ACTION_NOT_VALID;
   }

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

अधिक स्पष्टीकरण के लिए निम्न लिंक देखें


-1

यदि आप एक डिफ़ॉल्ट मान चाहते हैं और लुकअप मैप्स का निर्माण नहीं करना चाहते हैं, तो आप इसे संभालने के लिए एक स्थिर विधि बना सकते हैं। यह उदाहरण भी लुकअप को संभालता है जहाँ अपेक्षित नाम एक संख्या के साथ शुरू होगा।

    public static final Verbosity lookup(String name) {
        return lookup(name, null);
    }

    public static final Verbosity lookup(String name, Verbosity dflt) {
        if (StringUtils.isBlank(name)) {
            return dflt;
        }
        if (name.matches("^\\d.*")) {
            name = "_"+name;
        }
        try {
            return Verbosity.valueOf(name);
        } catch (IllegalArgumentException e) {
            return dflt;
        }
    }

यदि आपको एक द्वितीयक मूल्य पर इसकी आवश्यकता है, तो आप पहले लुकअप मैप का निर्माण करेंगे जैसे कि कुछ अन्य उत्तरों में।


-1
public enum EnumRole {

ROLE_ANONYMOUS_USER_ROLE ("anonymous user role"),
ROLE_INTERNAL ("internal role");

private String roleName;

public String getRoleName() {
    return roleName;
}

EnumRole(String roleName) {
    this.roleName = roleName;
}

public static final EnumRole getByValue(String value){
    return Arrays.stream(EnumRole.values()).filter(enumRole -> enumRole.roleName.equals(value)).findFirst().orElse(ROLE_ANONYMOUS_USER_ROLE);
}

public static void main(String[] args) {
    System.out.println(getByValue("internal role").roleName);
}

}


-2

आप Enum::valueOf()फ़ंक्शन का उपयोग ऊपर गैरेथ डेविस और ब्रैड मेस द्वारा सुझाए गए तरीके से कर सकते हैं , लेकिन सुनिश्चित करें कि आप इसे संभाल IllegalArgumentExceptionलेंगे, अगर इस्तेमाल किया गया स्ट्रिंग एनम में मौजूद नहीं है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.