Enum ordinal से enum type में कन्वर्ट करें


315

मेरे पास एनुम प्रकार ReportTypeEnumहै जो मेरी सभी कक्षाओं में विधियों के बीच पास हो जाता है, लेकिन फिर मुझे इसे URL पर पारित करने की आवश्यकता होती है, इसलिए मैं अंतरंग मान प्राप्त करने के लिए क्रमिक विधि का उपयोग करता हूं। अपने अन्य JSP पेज में इसे प्राप्त करने के बाद, मुझे इसे वापस बदलने की आवश्यकता है ReportTypeEnumताकि मैं इसे जारी रख सकूं।

मैं अध्यादेश को कैसे परिवर्तित कर सकता हूं ReportTypeEnum?

जावा 6 एसई का उपयोग करना।


1
जावा 6 ईई नहीं है, अब तक (एएफएआईके)। जावा एसई 6, और जावा ईई 5.
होसम एलि

जवाबों:


632

एक ऑर्डिनल को अपने एनम रिप्रजेंटेशन में बदलने के लिए आप ऐसा करना चाहते हैं:

ReportTypeEnum value = ReportTypeEnum.values()[ordinal];

कृपया सरणी सीमा पर ध्यान दें।

ध्यान दें कि हर कॉल values()एक नए क्लोन सरणी देता है जो प्रदर्शन को नकारात्मक तरीके से प्रभावित कर सकता है। आप सरणी को कैश करना चाह सकते हैं यदि इसे अक्सर कहा जा रहा है।

कैश करने के तरीके पर कोड उदाहरणvalues()


इस जवाब को टिप्पणियों के अंदर दिए गए फीडबैक को शामिल करने के लिए संपादित किया गया था


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

@IcesDante: निश्चित रूप से स्रोत में गणना मूल्यों के क्रम के अनुरूप होने की गारंटी दी जाती है। यदि आप एक अलग व्यवहार का निरीक्षण करते हैं, तो कुछ और गलत होना चाहिए। हालाँकि, ऊपर दिए गए मेरे जवाब अन्य उत्तरों में निर्धारित सभी कारणों के लिए उप-रूपी हैं।
जोकिम सॉर

137

यह लगभग निश्चित रूप से एक बुरा विचार है । निश्चित रूप से अगर ऑर्डिनल डी-फैक्टो बना रहता है (जैसे कि किसी ने URL को बुकमार्क किया है) - इसका मतलब है कि आपको हमेशा इसे संरक्षित रखना चाहिएenum भविष्य में ऑर्डर , जो कि लाइन मेंटेनर को कोड करने के लिए स्पष्ट नहीं हो सकता है।

इसके बजाय enumउपयोग myEnumValue.name()(और डीकोड के माध्यम से ReportTypeEnum.valueOf(s)) को एन्कोड क्यों नहीं किया जाता है?


24
क्या होगा यदि आप एनम का नाम बदलते हैं (लेकिन ऑर्डर रखें)?
आर्ने एवरटसन 15

6
@Arne - मुझे लगता है कि यह कुछ अनुभवहीन व्यक्ति के साथ आने और valueया तो शुरुआत में जोड़ने या इसकी सही वर्णमाला / तार्किक स्थिति की तुलना में बहुत कम है । (तार्किक रूप से मेरा मतलब है उदाहरण के लिए TimeUnitमानों का एक तार्किक स्थान है)
oxbow_lakes

7
मैं निश्चित रूप से अपने एनम के नाम के बजाय एनमेस ऑर्डर को बाध्य करना पसंद करता हूं ... यही कारण है कि मैं डेटाबेस में एनम के नाम के बजाय ऑर्डिनल को स्टोर करना पसंद करता हूं। इसके अलावा, स्ट्रिंग के बजाय इंट हेरफेर का उपयोग करना बेहतर है ...

8
मैं सहमत हूँ। एक सार्वजनिक एपीआई में, एनम का नाम बदलने से पिछड़े संगतता को तोड़ दिया जाएगा, लेकिन आदेश को बदलना नहीं होगा। इस कारण से, यह आपके "कुंजी" के रूप में नाम का उपयोग करने के लिए अधिक समझ में आता है
नोएल

3
अध्यादेश को संग्रहीत करने से आपके विचारों को अन्य भाषाओं में अनुवाद करना आसान हो जाता है। यदि आपको C में कुछ घटक लिखने की आवश्यकता हो तो क्या होगा?
QED

94

अगर मैं values()बहुत उपयोग कर रहा हूं :

enum Suit {
   Hearts, Diamonds, Spades, Clubs;
   public static final Suit values[] = values();
}

इस बीच जहाँ कहीं भी। जावा:

Suit suit = Suit.values[ordinal];

अपने सरणी सीमा मन।


3
+1 यह अब तक का सबसे अच्छा समाधान IMHO है क्योंकि कोई विशेष रूप से android.os.Message में अध्यादेश पास कर सकता है।
likejudo

9
यह बहुत चिंताजनक है क्योंकि सरणियाँ परस्पर हैं । भले ही मान [] अंतिम हो, यह Suit.values[0] = Suit.Diamonds;आपके कोड में कहीं नहीं रोकता है। आदर्श रूप से ऐसा कभी नहीं होगा, लेकिन परिवर्तनशील क्षेत्रों को उजागर नहीं करने का समग्र सिद्धांत अभी भी है। इस दृष्टिकोण के लिए, Collections.unmodifiableListइसके बजाय उपयोग या पसंद पर विचार करें ।
मश्निक

कैसे के बारे में - निजी स्थिर अंतिम सूट मान [] = मान (); सार्वजनिक स्थैतिक सूट [] getValues ​​() {वापसी मान; }
प्रत्यूष

4
@Pratyush जो सरणी चर को अपरिवर्तनीय बना देगा, लेकिन इसकी सामग्री नहीं। मैं अभी भी getValues ​​() [0] = कुछ कर सकता था;
कैलाबासिन

सहमत, इस प्रकार यह बिंदु Suit values[]प्रत्यक्ष या अप्रत्यक्ष रूप से उजागर नहीं होता है (कैसे के माध्यम से उल्लेख किया गया था getValues()), मैं एक सार्वजनिक विधि के साथ काम करता हूं जहां ordinalमूल्य को भेजा जाना चाहिए कि कैसे एक तर्क है और Suitप्रतिनिधित्व को वापस लौटाएं Suit values[]। यहाँ बिंदु (शुरुआत से प्रश्न की टाइल) एक एनुम ऑर्डिनल से एक एनुम प्रकार का निर्माण किया गया था
मैनुअल जॉर्डन

13

मैं ज्यादातर लोगों से सहमत हूं कि अध्यादेश का उपयोग करना शायद एक बुरा विचार है। मैं आमतौर पर एनम को एक निजी निर्माता को देकर इस समस्या को हल करता हूं जो उदाहरण के लिए डीबी मान ले सकता है फिर fromDbValueजनवरी के उत्तर में एक के समान एक स्थिर फ़ंक्शन बना सकता है।

public enum ReportTypeEnum {
    R1(1),
    R2(2),
    R3(3),
    R4(4),
    R5(5),
    R6(6),
    R7(7),
    R8(8);

    private static Logger log = LoggerFactory.getLogger(ReportEnumType.class);  
    private static Map<Integer, ReportTypeEnum> lookup;
    private Integer dbValue;

    private ReportTypeEnum(Integer dbValue) {
        this.dbValue = dbValue;
    }


    static {
        try {
            ReportTypeEnum[] vals = ReportTypeEnum.values();
            lookup = new HashMap<Integer, ReportTypeEnum>(vals.length);

            for (ReportTypeEnum  rpt: vals)
                lookup.put(rpt.getDbValue(), rpt);
         }
         catch (Exception e) {
             // Careful, if any exception is thrown out of a static block, the class
             // won't be initialized
             log.error("Unexpected exception initializing " + ReportTypeEnum.class, e);
         }
    }

    public static ReportTypeEnum fromDbValue(Integer dbValue) {
        return lookup.get(dbValue);
    }

    public Integer getDbValue() {
        return this.dbValue;
    }

}

अब आप लुकअप को बदले और इसके विपरीत ऑर्डर को बदल सकते हैं।


यह सही जवाब है। मुझे आश्चर्य है कि अन्य अधिक प्रत्यक्ष लेकिन संभावित अमान्य उत्तरों (भविष्य में कोड में बदलाव के कारण) की तुलना में इसे कुछ अंक मिले हैं।
कैलाबासिन

8

आप एक स्थिर लुकअप तालिका का उपयोग कर सकते हैं:

public enum Suit {
  spades, hearts, diamonds, clubs;

  private static final Map<Integer, Suit> lookup = new HashMap<Integer, Suit>();

  static{
    int ordinal = 0;
    for (Suit suit : EnumSet.allOf(Suit.class)) {
      lookup.put(ordinal, suit);
      ordinal+= 1;
    }
  }

  public Suit fromOrdinal(int ordinal) {
    return lookup.get(ordinal);
  }
}

3
Enums भी देखें ।
ट्रैशगोड

11
वाह! बस वाह! यह साफ है, निश्चित रूप से, लेकिन ... आप जानते हैं - मेरे अंदर का सी प्रोग्रामर दर्द में चीखता है यह देखकर कि आप एक पूर्ण विकसित हाशप को आवंटित करते हैं और इसके अंदर लुकअप करते हैं, यह जरूरी है कि केवल 4 स्थिरांक का प्रबंधन करें: हुकुम, दिल। हीरे और क्लब! एसी प्रोग्रामर प्रत्येक के लिए 1 बाइट आवंटित करेगा: 'कास्ट चार CLUBS = 0;' आदि ... हाँ, एक हैशपॉप लुक ओ (1) है, लेकिन मेमोरी और सीपीयू ओवरहैड का हैशपॉप, इस मामले में इसे कॉलिंग .values ​​() से सीधे भूख और धीमी गति के संसाधन के कई आदेश बनाते हैं! कोई आश्चर्य नहीं कि जावा ऐसी मेमोरी हॉग है यदि लोग इस तरह लिखते हैं ...
लेसजेक

2
हर कार्यक्रम को ट्रिपल ए गेम के प्रदर्शन की आवश्यकता नहीं होती है। कई मामलों में टाइप सेफ्टी, पठनीयता, मेंटेनेंस, क्रॉस प्लेटफॉर्म सपोर्ट, गारबेज कलेक्शन आदि के लिए मेमोरी और सीपीयू ट्रेडिंग करना उचित है। उच्च स्तरीय भाषाएं एक कारण से मौजूद हैं।
जनवरी

3
लेकिन अगर आपकी मुख्य सीमा हमेशा होती है 0...(n-1), तो एक सरणी कम कोड और अधिक पठनीय होती है; प्रदर्शन को बढ़ावा देना सिर्फ एक बोनस है। private static final Suit[] VALUES = values();और public Suit fromOrdinal(int ordinal) { return VALUES[ordinal]; }। अतिरिक्त लाभ: चुपचाप वापस लौटने के बजाय, अमान्य अध्यादेशों पर तुरंत क्रैश हो जाता है। (हमेशा एक फायदा नहीं। लेकिन अक्सर।)
थॉमस

4

यही है वह जो मेरे द्वारा उपयोग किया जाता है। मैं कोई दिखावा नहीं करता कि यह ऊपर के सरल समाधानों की तुलना में बहुत कम "कुशल" है। यह क्या करता है "ArrayIndexOutOfBounds" की तुलना में एक बहुत स्पष्ट अपवाद संदेश प्रदान करता है जब उपरोक्त समाधान में एक अमान्य अध्यादेश मूल्य का उपयोग किया जाता है।

यह इस तथ्य का उपयोग करता है कि EnumSet javadoc इट्रेटर रिटर्न तत्वों को उनके प्राकृतिक क्रम में निर्दिष्ट करता है। अगर यह सही नहीं है तो एक जोर है।

JUnit4 टेस्ट दर्शाता है कि इसका उपयोग कैसे किया जाता है।

 /**
 * convert ordinal to Enum
 * @param clzz may not be null
 * @param ordinal
 * @return e with e.ordinal( ) == ordinal
 * @throws IllegalArgumentException if ordinal out of range
 */
public static <E extends Enum<E> > E lookupEnum(Class<E> clzz, int ordinal) {
    EnumSet<E> set = EnumSet.allOf(clzz);
    if (ordinal < set.size()) {
        Iterator<E> iter = set.iterator();
        for (int i = 0; i < ordinal; i++) {
            iter.next();
        }
        E rval = iter.next();
        assert(rval.ordinal() == ordinal);
        return rval;
    }
    throw new IllegalArgumentException("Invalid value " + ordinal + " for " + clzz.getName( ) + ", must be < " + set.size());
}

@Test
public void lookupTest( ) {
    java.util.concurrent.TimeUnit tu = lookupEnum(TimeUnit.class, 3);
    System.out.println(tu);
}

1

यह वही है जो मैं एंड्रॉइड पर प्रोगार्ड के साथ करता हूं:

public enum SomeStatus {
    UNINITIALIZED, STATUS_1, RESERVED_1, STATUS_2, RESERVED_2, STATUS_3;//do not change order

    private static SomeStatus[] values = null;
    public static SomeStatus fromInteger(int i) {
        if(SomeStatus.values == null) {
            SomeStatus.values = SomeStatus.values();
        }
        if (i < 0) return SomeStatus.values[0];
        if (i >= SomeStatus.values.length) return SomeStatus.values[0];
        return SomeStatus.values[i];
    }
}

यह छोटा है और मुझे प्रोगार्ड में अपवाद होने की चिंता करने की आवश्यकता नहीं है


1

आप एक सरल विधि को परिभाषित कर सकते हैं जैसे:

public enum Alphabet{
    A,B,C,D;

    public static Alphabet get(int index){
        return Alphabet.values()[index];
    }
}

और इसका उपयोग करें:

System.out.println(Alphabet.get(2));

0
public enum Suit implements java.io.Serializable, Comparable<Suit>{
  spades, hearts, diamonds, clubs;
  private static final Suit [] lookup  = Suit.values();
  public Suit fromOrdinal(int ordinal) {
    if(ordinal< 1 || ordinal> 3) return null;
    return lookup[value-1];
  }
}

परीक्षण वर्ग

public class MainTest {
    public static void main(String[] args) {
        Suit d3 = Suit.diamonds;
        Suit d3Test = Suit.fromOrdinal(2);
        if(d3.equals(d3Test)){
            System.out.println("Susses");
        }else System.out.println("Fails");
    }
}

मैं सराहना करता हूं कि आप हमारे साथ साझा करते हैं यदि आपके पास अधिक कुशल कोड है, तो मेरा एनम विशाल है और लगातार हजारों बार कहा जाता है।


मुझे लगता है कि आपका मतलब था "अगर (क्रमिक <1 || क्रमिक> 4) वापसी शून्य?"
जेवर

0

तो एक तरीका यह है कि ExampleEnum valueOfOrdinal = ExampleEnum.values()[ordinal];कौन सा काम करता है और यह आसान है, हालांकि, जैसा कि पहले बताया गया है, ExampleEnum.values()हर कॉल के लिए एक नया क्लोन सरणी देता है। जो बेवजह महंगा हो सकता है। हम एरे को कैशिंग करके हल कर सकते हैं ExampleEnum[] values = values()। हमारे कैश्ड सरणी को संशोधित करने की अनुमति देना भी "खतरनाक" है। कोई लिख सकता है ExampleEnum.values[0] = ExampleEnum.type2;तो मैं इसे एक्सेसर विधि से निजी बनाऊंगा जो अतिरिक्त प्रतिलिपि नहीं करता है।

private enum ExampleEnum{
    type0, type1, type2, type3;
    private static final ExampleEnum[] values = values();
    public static ExampleEnum value(int ord) {
        return values[ord];
    }
}

आप ExampleEnum.value(ordinal)एनम मूल्य के साथ जुड़े पाने के लिए उपयोग करेंगेordinal


-1

हर एनम का नाम () है, जो एनम सदस्य के नाम के साथ एक स्ट्रिंग देता है।

दिया enum Suit{Heart, Spade, Club, Diamond}, Suit.Heart.name()देगाHeart

प्रत्येक एनुम में एक valueOf()विधि होती है, जो रिवर्स ऑपरेशन करने के लिए एक एनुम प्रकार और एक स्ट्रिंग लेती है:

Enum.valueOf(Suit.class, "Heart") रिटर्न Suit.Heart

कोई भी अध्यादेश का उपयोग क्यों करेगा यह मेरे से परे है। यह नैनोसेकंड तेजी से हो सकता है, लेकिन यह सुरक्षित नहीं है, अगर एनम के सदस्य बदलते हैं, क्योंकि किसी अन्य डेवलपर को पता नहीं हो सकता है कि कुछ कोड सामान्य मानों पर निर्भर है (विशेषकर जेएसपी पृष्ठ में सवाल का हवाला दिया गया है, नेटवर्क और डेटाबेस ओवरहेड हावी है समय, एक स्ट्रिंग पर पूर्णांक का उपयोग नहीं करना)।


2
क्योंकि तार की तुलना की तुलना में पूर्णांकों की तुलना बहुत तेज है?
HighCommander4

2
लेकिन अगर कोई एनम (एड्स / रीमॉड मेमर्स) को संशोधित करता है, तो अध्यादेश बदल जाएगा। कभी-कभी यह सुरक्षा और गति के बारे में नहीं है, विशेष रूप से एक जेएसपी पृष्ठ पर जहां नेटवर्क विलंबता एक पूर्णांक (एक स्ट्रिंग) और एक पूर्णांक की एक सरणी की तुलना करने के बीच के अंतर का 1,000,000 गुना है।
टोनी बेनब्राहिम

.Strring को ओवरराइड किया जा सकता है, इसलिए हो सकता है कि वह एनम नाम वापस न करे। विधि का नाम () क्या है जो
एनम

कोड टिप्पणी और अनुप्रयोग संस्करण भी एक चीज है (शायद एक फ़ाइल प्रारूप सरल और इस तरह से छोटा है)
जो पेलेटियर

यह निश्चित नहीं है कि जब यह अनिवार्य रूप से उसी चीज़ की सिफारिश कर रहा था जो oxbow_lakes के उत्तर में थी। क्रमिक उपयोग करने से निश्चित रूप से सुरक्षित।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.