इंटम को इंट वैल्यू के साथ जोड़ा जा रहा है


89

इससे पहले, मैं अपने लेगनो एनमों को बस के रूप में परिभाषित करता था:

NO_LEG, LEG_ONE, LEG_TWO

और कॉल करके return LegNo.values()[i];, मैं प्रत्येक एनम के साथ जुड़े मूल्य प्राप्त करने में सक्षम था।

लेकिन अब मैंने तय कर लिया है कि मैं चाहता हूं कि LegNoएनम NO_LEG0 के बजाय इंट -1 हो, इसलिए मैंने एक निजी कंस्ट्रक्टर का उपयोग इनिशियलाइज़ करने और उसका मान सेट करने का निर्णय लिया

NO_LEG(-1), LEG_ONE(1), LEG_TWO(2);

private LegNo(final int leg) { legNo = leg; }

अब केवल एक चीज यह है कि क्योंकि मैं इसे इस तरह से कर रहा हूं कि यह values()विधि NO_LEGएनम के लिए काम नहीं करेगी । मुझे इंट से जुड़ी हुई एनम कैसे मिलती है? क्या केस स्विच स्टेटमेंट का उपयोग करने या इफिस-हनीफ के अलावा ऐसा करने का कोई कुशल तरीका है

मैं बहुत सारे एसओ सवालों को एनम से अंतर मान प्राप्त करने के लिए देख सकता हूं, लेकिन मैं इसके बाद हूं।

जवाबों:


148

EDIT अगस्त 2018

आज मैं इसे इस प्रकार लागू करूंगा

public enum LegNo {
    NO_LEG(-1), LEG_ONE(1), LEG_TWO(2);

    private final int value;

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

    public static Optional<LegNo> valueOf(int value) {
        return Arrays.stream(values())
            .filter(legNo -> legNo.value == value)
            .findFirst();
    }
}

आपको एनम के अंदर एक मैपिंग को बनाए रखना होगा।

public enum LegNo {
    NO_LEG(-1), LEG_ONE(1), LEG_TWO(2);

    private int legNo;

    private static Map<Integer, LegNo> map = new HashMap<Integer, LegNo>();

    static {
        for (LegNo legEnum : LegNo.values()) {
            map.put(legEnum.legNo, legEnum);
        }
    }

    private LegNo(final int leg) { legNo = leg; }

    public static LegNo valueOf(int legNo) {
        return map.get(legNo);
    }
}

स्टैटिक ब्लॉक को केवल एक बार लागू किया जाएगा, इसलिए यहां व्यावहारिक रूप से कोई प्रदर्शन मुद्दा नहीं है।

संपादित करें: valueOfअन्य जावा कक्षाओं के साथ अधिक इनलाइन होने के कारण विधि का नाम बदला ।


खेद है कि यकीन नहीं है कि अगर मैं पर्याप्त स्पष्ट था। मैं इंट में पास होना चाहता हूं और इसके साथ जुड़ी हुई एनम प्राप्त करना चाहता हूं।
एल-सैमुअल्स

@ L-Samuels लगता है कि मैंने आपके प्रश्न को ठीक से नहीं पढ़ा है। मेरा अपडेट देखें।
अदर्सहर

2
मैं जानता हूँ कि यह स्पष्ट लगता है, लेकिन यह इतना चाहते का उपयोग करें: LegNo foo = LegNo.valueOf(2);। पिछला कोड वापस आ जाएगा LegNo.LEG_TWO
फर्स्टऑन

1
ध्यान दिया जाए, तो एक अमान्य पूर्णांक मान (मैप नहीं किया गया) वापस आ जाएगा null, जैसा कि HashMap.get का उपयोग करके अपेक्षित है : वह मान लौटाता है जिसमें निर्दिष्ट कुंजी मैप की गई है, या रिक्त है यदि इस मैप में कुंजी के लिए कोई मैपिंग नहीं है।
फर्स्टऑन

जबकि स्ट्रीम सिंटैक्स साफ-सुथरा है, यह इंगित करने के लायक है कि इसमें स्थैतिक मानचित्र की तुलना में अधिक समय की जटिलता है (जो माना जाता है कि इसमें मेमोरी की खपत अधिक है)। 3 मानों के लिए कोई समस्या नहीं है, लेकिन निश्चित रूप से एक चिंता का विषय है यदि आप valueOf()किसी अन्य लूप के अंदर 1000 सदस्यीय एनुम का उपयोग कर रहे हैं ।
पैट्रिक एम

24

आप एनम में एक स्थिर विधि भी शामिल कर सकते हैं जो सभी सदस्यों के माध्यम से पुनरावृत्ति करता है और सही को लौटाता है।

public enum LegNo {
   NO_LEG(-1),
   LEG_ONE(1),
   LEG_TWO(2);

   private int legIndex;

   private LegNo(int legIndex) { this.legIndex = legIndex; }

   public static LegNo getLeg(int legIndex) {
      for (LegNo l : LegNo.values()) {
          if (l.legIndex == legIndex) return l;
      }
      throw new IllegalArgumentException("Leg not found. Amputated?");
   }
}

अब, यदि आप पूर्णांक द्वारा एनम मान प्राप्त करना चाहते हैं, तो आप इसका उपयोग करते हैं:

int myLegIndex = 1; //expected : LEG_ONE
LegNo myLeg = LegNo.getLeg(myLegIndex);

मुझे लगता है अगर यह एक और अगर बयान का उपयोग करने की तुलना में अधिक सुंदर होगा। लेकिन इसके बाद और अधिक खोज की गई, तब @adarshr द्वारा सुझाई गई मानचित्र रणनीति बेहतर होगी। हालांकि हास्य के लिए वोट करें।
एल-सैमुअल्स

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

आपको किसी भी संबंधित आयतन के मूल्य को उसके अध्यादेश से प्राप्त नहीं करना चाहिए। स्थैतिक मानचित्र का उपयोग जावा आर्किटेक्ट द्वारा अनुशंसित पद्धति है।
hfontanez 15

लेगइंडेक्स क्षेत्र इस उदाहरण में क्रमिक के साथ मेल खाता है, लेकिन कोई भी अंतर मूल्य हो सकता है। कोई ऑर्डिनल लुकअप नहीं किया जाता है। इसके अलावा, कृपया बताएं या लिंक करें कि आपको ऐसा क्यों लगता है कि ऑर्डिनल लुकअप खराब है।
माइक एडलर

1
"पैर नहीं मिला? विवादास्पद?"
ज्ञानी

17

adarshr का उत्तर जावा 8 के अनुकूल है:

import static java.util.Arrays.stream;
import static java.util.stream.Collectors.toMap;

import java.util.Map;

public enum LegNo {
    NO_LEG(-1), LEG_ONE(1), LEG_TWO(2);

    private final int legNo;

    private final static Map<Integer, LegNo> map =
            stream(LegNo.values()).collect(toMap(leg -> leg.legNo, leg -> leg));

    private LegNo(final int leg) {
        legNo = leg;
    }

    public static LegNo valueOf(int legNo) {
        return map.get(legNo);
    }
}

11

आप एनम लेगानो पर केवल मान () विधि से कॉल करके दिए गए पूर्णांक मान के अनुरूप एनुम मूल्य का उपयोग कर सकते हैं। यह लेगानो एनमों का क्षेत्र लौटाता है: LegNo.values()[0]; //returns LEG_NO LegNo.values()[1]; //returns LEG_ONE LegNo.values()[2]; //returns LEG_TWO

ठीक वह बात नहीं जो वह ढूंढ रहा था, लेकिन वास्तव में बहुत करीब और बहुत सरल है। (हालांकि विषय मृत है यह किसी और के लिए उपयोगी हो सकता है।)


6

डिफ़ॉल्ट मान के साथ जावा 8 रास्ता:

public enum LegNo {
    NO_LEG(-1), LEG_ONE(1), LEG_TWO(2);

    private final int legNo;

    LegNo(int legNo) {
        this.legNo = legNo;
    }

    public static LegNo find(int legNo, Supplier<? extends LegNo> byDef) {
        return Arrays.asList(LegNo.values()).stream()
                .filter(e -> e.legNo == legNo).findFirst().orElseGet(byDef);
    }
}

बुलाना:

LegNo res = LegNo.find(0, () -> LegNo.NO_LEG);

या अपवाद के साथ:

LegNo res = LegNo.find(0, () -> {
    throw new RuntimeException("No found");
});

2
public enum LegNo {

  NO_LEG(-1), LEG_ONE(1), LEG_TWO(2);

  private final int code;

  LegNo(int code) {
    this.code = code;
    ReverseStorage.reverseMap.put(code, this);
  }

  public static Optional<LegNo> getByCode(int code) {
    return Optional.ofNullable(ReverseStorage.reverseMap.get(code));
  }

  private static final class ReverseStorage {
    private static final Map<Integer, LegNo> reverseMap = new LinkedHashMap<>();
  }
}

1

चूँकि आपकी Enum में केवल 3 तत्व होते हैं, इसलिए सबसे तेज़ तरीका सिर्फ if elseआपके द्वारा सुझाई गई श्रृंखला का उपयोग करना होगा ।

संपादित करें: जो उत्तर एडारश ने प्रदान किया है वह सामान्य मामलों के लिए बेहतर है, जहां कई एनुम मूल्य हैं, लेकिन मुझे लगता है कि यह आपकी समस्या के लिए एक ओवरकिल है।


Mapआपके कोड में ए होना निश्चित रूप से ओवरकिल नहीं है। इसके अलावा, अगर-और शर्तों के स्पेगेटी की तुलना में यह विधि को बहुत अधिक स्वच्छ बनाता है।
आराध्य

मैं इस बात से सहमत हूं कि आपके पास बहुत सारे एनम वैल्यू होने के बाद मैप बेहतर है, लेकिन 3 वैल्यू के लिए मैं एक / दूसरे कंस्ट्रक्शन से चिपका रहूंगा। मुझे लगता है कि यह स्वाद की बात है।
डाइटरेडीडीपी

हम जो भी दृष्टिकोण चुनते हैं, उसके विधि हस्ताक्षर public LegNo valueOf(int value)को नहीं बदलना चाहिए। अगर-और फिर एनम के भीतर लिखा जा सकता है। अगर इनेमल से बाहर निकलता है, तो यह निश्चित रूप से एक साफ-सुथरा कोड बन जाता है।
अदर्शन

1
मैं आपसे पूरी तरह से सहमत हूं :)
डाइटरीडीपी

1
public enum LegNo {
    NO_LEG(-1), LEG_ONE(1), LEG_TWO(2);

    private int legNo;

    private LegNo(int leg) { legNo = leg; }

    public static LegNo valueOf(int legNo) {
        for (LegNo leg : LegNo.values()) {
            if (leg.legNo == legNo) return leg;
        }   
    }
}

assert LegNo.valueOf(2) == LegNo.LEG_TWO
assert LegNo.valueOf(3) == null

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