जावा Enum के मिलान के लिए पूर्णांक मान बदलें


86

मेरे पास एक एनम है:

public enum PcapLinkType {
  DLT_NULL(0)
  DLT_EN10MB(1)
  DLT_EN3MB(2),
  DLT_AX25(3),
  /*snip, 200 more enums, not always consecutive.*/
  DLT_UNKNOWN(-1);
    private final int value;   

    PcapLinkType(int value) {
        this.value= value;
    }
}

अब मुझे बाहरी इनपुट से एक इंट मिलता है और मैचिंग इनपुट चाहता हूं - यदि कोई मूल्य मौजूद नहीं है तो एक अपवाद को फेंकना ठीक है, लेकिन अधिमानतः मैं DLT_UNKNOWN उस स्थिति में होगा।

int val = in.readInt();
PcapLinkType type = ???; /*convert val to a PcapLinkType */

जवाबों:


105

इंटेगर को मैप करने वाले वर्ग में आ स्थैतिक मानचित्र को जोड़कर आपको इसे मैन्युअल रूप से करने की आवश्यकता होगी, जैसे कि

private static final Map<Integer, PcapLinkType> intToTypeMap = new HashMap<Integer, PcapLinkType>();
static {
    for (PcapLinkType type : PcapLinkType.values()) {
        intToTypeMap.put(type.value, type);
    }
}

public static PcapLinkType fromInt(int i) {
    PcapLinkType type = intToTypeMap.get(Integer.valueOf(i));
    if (type == null) 
        return PcapLinkType.DLT_UNKNOWN;
    return type;
}

1
dty से सिफारिशों के साथ अद्यतन किया गया, जो एक अच्छा विचार था।
MeBigFatGuy

मुझे आशा है कि आपने पहले एक संकलक के माध्यम से मेरे कोड को चलाया ... मैंने अभी इसे अपने सिर के ऊपर से बनाया है। मुझे पता है कि तकनीक काम करती है - मैंने कल इसका इस्तेमाल किया। लेकिन कोड किसी अन्य मशीन पर है और यह मेरे देव उपकरण नहीं है।
dty

1
allOf केवल सेट्स के लिए उपलब्ध है
MeBigFatGuy

1
इसके अलावा, EnumMapचाबियाँ के रूप में enums का उपयोग करता है। इस मामले में, ओपी एनमों को मूल्यों के रूप में चाहता है।
dty

8
यह बहुत सारे अनावश्यक ओवरहेड की तरह लगता है। जिन लोगों को वास्तव में इस प्रकार के ऑपरेशन की आवश्यकता होती है, उन्हें शायद उच्च प्रदर्शन की आवश्यकता होती है क्योंकि वे स्ट्रीम / सॉकेट से लिख रहे हैं / पढ़ रहे हैं, इस स्थिति में, values()(यदि आपके एनम मान अनुक्रमिक हैं) कैशिंग या एक सरल switchकथन इस विधि को आसानी से हरा देगा। । यदि आपके पास केवल एक मुट्ठी भर प्रविष्टियाँ हैं, Enumतो switchस्टेटमेंट को अपडेट नहीं करने की सुविधा के लिए हैशपॉप के ओवरहेड को जोड़ने का कोई मतलब नहीं है । यह विधि अधिक सुरुचिपूर्ण लग सकती है, लेकिन यह भी बेकार है।
कुचलने

30

वहाँ एक स्थिर विधि है values()जो है प्रलेखित, लेकिन आप इसे नहीं उम्मीद थी जहां: http://docs.oracle.com/javase/tutorial/java/javaOO/enum.html

enum MyEnum {
    FIRST, SECOND, THIRD;
    private static MyEnum[] allValues = values();
    public static MyEnum fromOrdinal(int n) {return allValues[n];}
}

सिद्धांत रूप में, आप बस उपयोग कर सकते हैं values()[i], लेकिन ऐसी अफवाहें हैं जो values()हर बार इसे लागू किए जाने पर सरणी की एक प्रति बनाएंगे।


9
यहोशू बलोच (प्रभावी जावा बुक) के अनुसार : कभी भी अपने अध्यादेश के किसी एनम से जुड़े मूल्य को प्राप्त न करें ; आपका कार्यान्वयन enums ऑर्डर पर निर्भर नहीं होना चाहिए।
stevo.mit 15

4
किस बात का क्रियान्वयन ? यदि हम कुछ एल्गोरिथ्म को लागू करते हैं, तो कार्यान्वयन को एनमेस ऑर्डर पर भरोसा नहीं करना चाहिए जब तक कि उस ऑर्डर को दस्तावेज नहीं किया जाता है। जब हम एनम को स्वयं कार्यान्वित करते हैं, तो इस तरह के कार्यान्वयन विवरण का उपयोग करना ठीक है, उसी तरह कक्षा-निजी तरीकों का उपयोग करना ठीक है।
18446744073709551615

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

4
@ stevo.mit की नई enum java.time पर एक नजर है। जावा में 8. महीना। महीना (int) स्थिर विधि बिल्कुल वही करती है जो जोशुआ बलोच ने कहा कि आपको "कभी नहीं" करना चाहिए। यह अपने क्रम के आधार पर एक महीना लौटाता है।
क्लिटोस काइराको

1
@ stevo.mit वहाँ रहे हैं आदेश दिया enums और अव्यवस्थित enums । (और बिटमस्क एनम भी।) केवल "एनम" के रूप में उनके बारे में बात करना गलत है। किस अभिव्यंजक का उपयोग करने का निर्णय आपके द्वारा काम किए जाने वाले अमूर्तता के स्तर पर आधारित होना चाहिए । कार्यान्वयन विवरण (निचले स्तर से अभिव्यंजक साधन) या उपयोग मान्यताओं (उच्च स्तर से अर्थपूर्ण अर्थ) का उपयोग करना वास्तव में गलत है। जैसा कि " कभी नहीं ", मानव भाषाओं में कभी भी कभी नहीं होता है, क्योंकि हमेशा कुछ संदर्भ होता है। (आमतौर पर, अनुप्रयोग प्रोग्रामिंग में, कभी नहीं ...) Btw, programering.com/a/MzNxQjMwATM.html
18446744073709551615

14

आपको एक नई स्थैतिक विधि बनानी होगी, जहाँ आप PcapLinkType.values ​​() को पुनरावृत्त करते हैं और तुलना करते हैं:

public static PcapLinkType forCode(int code) {
    for (PcapLinkType typе : PcapLinkType.values()) {
        if (type.getValue() == code) {
            return type;
        }
    }
    return null;
 }

यह ठीक है अगर इसे शायद ही कभी कहा जाता है। यदि इसे अक्सर कहा जाता है, तो Mapदूसरों द्वारा सुझाए गए अनुकूलन को देखें।


4
बहुत महंगा कहे जाने पर महंगा हो सकता है। स्थिर नक्शे का निर्माण बेहतर परिशोधन लागत देने की संभावना है।
दिनांक

@dty o (n) n = 200 के साथ - मुझे नहीं लगता कि इसका कोई मुद्दा है
Bozho

7
यह पूरी तरह से एक हास्यास्पद बयान है कि यह कितनी बार कहा जाता है। अगर इसे एक बार बुलाया जाए, तो ठीक है। यदि इसे 10Ge नेटवर्क पर पिछले हर पैकेट के लिए कॉल किया जाता है, तो एक एल्गोरिथ्म 200x तेज बनाना बहुत महत्वपूर्ण है। इसलिए मैंने "अगर बहुत कहा जाता है" के साथ अपने बयान को योग्य बनाया
डटी

10

आप उन सभी को स्वचालित रूप से उन सभी को एक संग्रह में पंजीकृत करने के लिए ऐसा कर सकते हैं, जिसके साथ आसानी से पूर्णांक को संबंधित एनम में बदल सकते हैं। (बीटीडब्ल्यू, उन्हें एनम कंस्ट्रक्टर में नक्शे में जोड़ने की अनुमति नहीं है । जावा जावा का उपयोग करने के कई बाद भी नई चीजें सीखना अच्छा है। :)

public enum PcapLinkType {
    DLT_NULL(0),
    DLT_EN10MB(1),
    DLT_EN3MB(2),
    DLT_AX25(3),
    /*snip, 200 more enums, not always consecutive.*/
    DLT_UNKNOWN(-1);

    private static final Map<Integer, PcapLinkType> typesByValue = new HashMap<Integer, PcapLinkType>();

    static {
        for (PcapLinkType type : PcapLinkType.values()) {
            typesByValue.put(type.value, type);
        }
    }

    private final int value;

    private PcapLinkType(int value) {
        this.value = value;
    }

    public static PcapLinkType forValue(int value) {
        return typesByValue.get(value);
    }
}

1
पोस्टिंग से पहले अपने जवाब को दोबारा जाँचने के लिए आपको यही मिलता है। ;)
एस्को लुओंटोला

10

अगर आपके पास इस तरह से एनम है

public enum PcapLinkType {
  DLT_NULL(0)
  DLT_EN10MB(1)
  DLT_EN3MB(2),
  DLT_AX25(3),
  DLT_UNKNOWN(-1);

    private final int value;   

    PcapLinkType(int value) {
        this.value= value;
    }
}

तो आप इसे पसंद कर सकते हैं

PcapLinkType type = PcapLinkType.values()[1]; /*convert val to a PcapLinkType */

आपने टिप्पणी को याद किया / * स्निप, 200 और एनुम्स, हमेशा लगातार नहीं। * /
MeBigFatGuy

बस अगर आपकी
एनम वैल्यू

4

जैसा कि @MeBigFatGuy कहता है, सिवाय इसके कि आप संग्रह static {...}पर अपने ब्लॉक का उपयोग कर सकते हैं values():

static {
    for (PcapLinkType type : PcapLinkType.values()) {
        intToTypeMap.put(type.getValue(), type);
    }
}

4

मुझे पता है कि यह प्रश्न कुछ साल पुराना है, लेकिन जैसा कि जावा 8 ने कहा है, इस बीच, हमें लाया Optional, मैंने सोचा कि मैं इसका उपयोग करके एक समाधान प्रस्तुत करूँगा ( Streamऔर Collectors):

public enum PcapLinkType {
  DLT_NULL(0),
  DLT_EN3MB(2),
  DLT_AX25(3),
  /*snip, 200 more enums, not always consecutive.*/
  // DLT_UNKNOWN(-1); // <--- NO LONGER NEEDED

  private final int value;
  private PcapLinkType(int value) { this.value = value; }

  private static final Map<Integer, PcapLinkType> map;
  static {
    map = Arrays.stream(values())
        .collect(Collectors.toMap(e -> e.value, e -> e));
  }

  public static Optional<PcapLinkType> fromInt(int value) {
    return Optional.ofNullable(map.get(value));
  }
}

Optionalऐसा है null: यह एक मामले का प्रतिनिधित्व करता है जब कोई (वैध) मूल्य नहीं होता है। लेकिन यह एक अधिक प्रकार-सुरक्षित विकल्प nullया डिफ़ॉल्ट मान है जैसे DLT_UNKNOWNकि आप nullया DLT_UNKNOWNमामलों की जांच करना भूल सकते हैं। वे दोनों मान्य PcapLinkTypeमूल्य हैं! इसके विपरीत, आप Optional<PcapLinkType>किसी वैरिएबल के प्रकार के लिए मान निर्दिष्ट नहीं कर सकते PcapLinkTypeOptionalआपको पहले वैध मान के लिए जाँच करता है।

बेशक, यदि आप DLT_UNKNOWNपिछड़ी अनुकूलता या किसी अन्य कारण से इसे बनाए रखना चाहते हैं, तो आप अभी Optionalभी उस स्थिति में भी इसका उपयोग कर सकते हैं , orElse()इसे डिफ़ॉल्ट मान के रूप में निर्दिष्ट करने के लिए उपयोग कर रहे हैं:

public enum PcapLinkType {
  DLT_NULL(0),
  DLT_EN3MB(2),
  DLT_AX25(3),
  /*snip, 200 more enums, not always consecutive.*/
  DLT_UNKNOWN(-1);

  private final int value;
  private PcapLinkType(int value) { this.value = value; }

  private static final Map<Integer, PcapLinkType> map;
  static {
    map = Arrays.stream(values())
        .collect(Collectors.toMap(e -> e.value, e -> e));
  }

  public static PcapLinkType fromInt(int value) {
    return Optional.ofNullable(map.get(value)).orElse(DLT_UNKNOWN);
  }
}

3

आप अपने एनम में एक स्थैतिक विधि जोड़ सकते हैं जो intएक पैरामीटर के रूप में स्वीकार करता है और रिटर्न देता है PcapLinkType

public static PcapLinkType of(int linkType) {

    switch (linkType) {
        case -1: return DLT_UNKNOWN
        case 0: return DLT_NULL;

        //ETC....

        default: return null;

    }
}

switchयदि आप नई एनम जोड़ते हैं, तो उस स्टेटमेंट में प्रविष्टि जोड़ना न भूलें । आदर्श नहीं, IMHO।
dty

1
@dty तो, आपको लगता है कि एक HashMap के ओवरहेड को स्विच स्टेटमेंट में एक नया केस जोड़ने की आवश्यकता है?
क्रश करें

1
मुझे लगता है कि मैं कोड लिखूंगा जो मुझे गलतियाँ नहीं करने में मदद करता है और इससे पहले कि मैं एक हैशटैग के सूक्ष्म प्रदर्शन पर ध्यान केंद्रित करने से पहले सही होने की अधिक संभावना है।
dty

3

यही है वह जो मेरे द्वारा उपयोग किया जाता है:

public enum Quality {ENOUGH,BETTER,BEST;
                     private static final int amount = EnumSet.allOf(Quality.class).size();
                     private static Quality[] val = new Quality[amount];
                     static{ for(Quality q:EnumSet.allOf(Quality.class)){ val[q.ordinal()]=q; } }
                     public static Quality fromInt(int i) { return val[i]; }
                     public Quality next() { return fromInt((ordinal()+1)%amount); }
                    }

सामान्य रूप से ऑर्डिनल का उपयोग खराब व्यवहार के रूप में किया गया है, इससे बचने के लिए बेहतर है।
राफेल

1
static final PcapLinkType[] values  = { DLT_NULL, DLT_EN10MB, DLT_EN3MB, null ...}    

...

public static PcapLinkType  getPcapLinkTypeForInt(int num){    
    try{    
       return values[int];    
    }catch(ArrayIndexOutOfBoundsException e){    
       return DLT_UKNOWN;    
    }    
}    

1
महँगा कहा जाए तो बहुत। सरणी को अपडेट करने के लिए याद रखने की आवश्यकता है (जब आपके पास यह भी हो, तो एनम एक .values()विधि को परिभाषित करते हैं ?)।
dty

@ यह कोशिश / पकड़ है? मुझे लगता है कि अगर बहुत सारे मूल्य DLT_UNKNOWN श्रेणी में आते हैं, तो इसे महंगा कहना उचित होगा।
nsfyn55

1
मैं एक सरणी समाधान को नीचे मतदान करते हुए देख रहा हूं और एक नक्शा समाधान ने मतदान को देखकर वास्तव में आश्चर्यचकित हूं। मैं यहाँ क्या नापसंद करता हूँ --int, लेकिन यह स्पष्ट रूप से एक टाइपो है।
18446744073709551615

मैं देख रहा हूँ: वे चाहते हैं nullके स्थान पर DLT_UKNOWN:)
18446744073709551615

1
क्यों नहीं static final values[] = PcapLinkType.values()?
18446744073709551615

0

पूर्णांक आधारित एन्यूमरेटेड प्रकारों को सुरुचिपूर्ण ढंग से संभालने का कोई तरीका नहीं है। आप अपने समाधान के बजाय एक स्ट्रिंग आधारित गणना का उपयोग करने के बारे में सोच सकते हैं। हर समय पसंदीदा तरीका नहीं है, लेकिन यह अभी भी मौजूद है।

public enum Port {
  /**
   * The default port for the push server.
   */
  DEFAULT("443"),

  /**
   * The alternative port that can be used to bypass firewall checks
   * made to the default <i>HTTPS</i> port.
   */
  ALTERNATIVE("2197");

  private final String portString;

  Port(final String portString) {
    this.portString = portString;
  }

  /**
   * Returns the port for given {@link Port} enumeration value.
   * @return The port of the push server host.
   */
  public Integer toInteger() {
    return Integer.parseInt(portString);
  }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.