जावा स्विच स्टेटमेंट: लगातार अभिव्यक्ति की आवश्यकता है, लेकिन यह स्थिर है


175

इसलिए, मैं इस वर्ग पर काम कर रहा हूं जिसमें कुछ स्थिर स्थिरांक हैं:

public abstract class Foo {
    ...
    public static final int BAR;
    public static final int BAZ;
    public static final int BAM;
    ...
}

फिर, मैं स्थिरांक के आधार पर एक प्रासंगिक स्ट्रिंग प्राप्त करने का एक तरीका चाहूंगा:

public static String lookup(int constant) {
    switch (constant) {
        case Foo.BAR: return "bar";
        case Foo.BAZ: return "baz";
        case Foo.BAM: return "bam";
        default: return "unknown";
    }
}

हालाँकि, जब मैं संकलित करता हूं, तो मुझे constant expression required3 केस लेबल में से प्रत्येक पर एक त्रुटि मिलती है ।

मैं समझता हूं कि संकलक को संकलित करने के लिए संकलित समय पर अभिव्यक्ति की आवश्यकता होती है, लेकिन Foo.BA_स्थिर क्यों नहीं है?


1
इस मामले में एक एनम का उपयोग नहीं करने का कोई कारण?
बैरक

1
मुझे नहीं लगा कि जावा में दुश्मनी थी। public static final ints JDK के माध्यम से सभी बिखरे हुए हैं, तो यही मैं साथ चला गया।
ऑस्टिन हाइड


4
और प्रभावी जावा ( java.sun.com/docs/books/effective ), आइटम 30 पढ़ें : इंट कॉन्स्टेंट के बजाय एनम का उपयोग करें
सीन पैट्रिक फ्लोयड

युक्तियाँ लोगों के लिए धन्यवाद, मैं उन लोगों की जाँच करूँगा।
ऑस्टिन हाइड

जवाबों:


150

मैं समझता हूं कि संकलक को संकलित करने के लिए संकलित समय पर अभिव्यक्ति की आवश्यकता होती है, लेकिन Foo.BA_ स्थिर क्यों नहीं है?

हालांकि वे किसी भी कोड के दृष्टिकोण से स्थिर होते हैं जो खेतों के प्रारंभिक होने के बाद निष्पादित होते हैं, वे जेएलएस द्वारा आवश्यक अर्थों में एक संकलन समय स्थिर नहीं होते हैं ; एक स्थिर अभिव्यक्ति 1 के विनिर्देशन के लिए specification15.28 लगातार अभिव्यक्तियाँ देखें । यह .44.12.4 फाइनल वेरिएबल्स को संदर्भित करता है जो "स्थिर चर" को परिभाषित करता है:

हम एक चर को आदिम प्रकार या टाइप स्ट्रिंग कहते हैं, जो एक अंतिम-समय स्थिर अभिव्यक्ति (a15.28) एक स्थिर चर के साथ आरंभिक है। वैरिएबल एक स्थिर वैरिएबल है या क्लास इनिशियलाइज़ेशन (is12.4.1), बाइनरी कम्पैटिबिलिटी (compatibility13.1, .413.4.9) और निश्चित असाइनमेंट ()16) के संबंध में निहितार्थ नहीं हो सकता है।

आपके उदाहरण में, Foo.BA * चर में इनिशियलाइज़र नहीं हैं, और इसलिए "निरंतर चर" के रूप में योग्य नहीं हैं। फिक्स सरल है; Foo.BA को बदलें। चर घोषणाओं में ऐसे कंपाइलर हैं जो संकलन-समय स्थिर अभिव्यक्ति हैं।

अन्य उदाहरणों में (जहाँ इनिशियलाइज़र्स पहले से ही कंपाइल-टाइम कंटीन्यूअस एक्सप्रेशन हैं), वैरिएबल को घोषित करना finalकि क्या जरूरत है।

आप अपने कोड को स्थिरांक के enumबजाय उपयोग करने के लिए बदल सकते हैं int, लेकिन यह विभिन्न प्रतिबंधों की एक और जोड़ी लाता है:


1 - निरंतर अभिव्यक्ति प्रतिबंधों को संक्षेप में निम्नानुसार किया जा सकता है। निरंतर अभिव्यक्तियाँ a) आदिम प्रकारों का उपयोग कर सकती हैं और Stringकेवल, b) उन प्राथमिकताओं को अनुमति देती हैं जो शाब्दिक हैं (इसके अलावा null) और निरंतर चर केवल, c) निरंतर अभिव्यक्तियों को संभवत: उप-विभाजनों के रूप में संक्षिप्त किया जा सकता है, घ) असाइनमेंट ऑपरेटरों ++, --या के अलावा ऑपरेटरों को अनुमति देते हैं , या instanceof, और ई) प्रकार की जातियों को आदिम प्रकार या Stringकेवल अनुमति देते हैं ।

ध्यान दें कि यह विधि या लैम्ब्डा कॉल के किसी भी रूप में शामिल नहीं है, , ।new या सरणी सबस्क्रिप्टिंग। इसके अलावा, सरणी मानों, मानों, आदिम आवरण प्रकारों के मूल्यों, बॉक्सिंग और अनबॉक्सिंग के सभी उपयोगों को क) के कारण बाहर रखा गया है।.class.lengthenum


79

आपको लगातार अभिव्यक्ति की आवश्यकता होती है क्योंकि आपने अपने स्थिरांक से मूल्यों को छोड़ दिया है। प्रयत्न:

public abstract class Foo {
    ...
    public static final int BAR=0;
    public static final int BAZ=1;
    public static final int BAM=2;
    ...
}

48

मुझे एंड्रॉइड पर यह त्रुटि मिली, और मेरा समाधान बस उपयोग करना था:

public static final int TAKE_PICTURE = 1;

के बजाय

public static int TAKE_PICTURE = 1;

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

4
मुझे पता है कि यह एक अलग समस्या है, लेकिन जब से मैं अपने साथ यहां आया हूं यह उसी स्थिति में किसी और की मदद कर सकता है।
टेओ इनके

समझ में आता है कि अगर चीजें इन मूल्यों को बदल सकती हैं तो वे गलत होंगे।
slott

31

क्योंकि वे समय संकलक नहीं हैं। निम्नलिखित मान्य कोड पर विचार करें:

public static final int BAR = new Random().nextInt();

आप केवल BARरनटाइम का मूल्य जान सकते हैं ।


1
दिलचस्प। चाहेंगे public static final int BAR = new Random().nextInt()काम करते हैं?
थिलो सेप

4
थिलो का बयान संकलित करता है लेकिन स्विच स्टेटमेंट निरंतर अभिव्यक्ति की आवश्यकता की शिकायत करता है । इसके अलावा, क्या दो लगातार new Random().nextInt()समान मान वापस नहीं ला सकते हैं?
टोनी एननिस

2
@ टोनी: जो एक अच्छी बात है। यह संकलन नहीं करता है क्योंकि यह संकलन-समय स्थिरांक के साथ आरंभ नहीं होता है। स्टीफन का स्वीकृत जवाब देखें। यदि वह संकलित करता है, तो एक यादृच्छिक पूर्णांक वर्ग में कठोर-कोडित किया जाएगा, जिसमें काफी अप्रत्याशित परिणाम होंगे।
थिलो सेप

मुझे आश्चर्य है कि स्विच में निरंतरता अस्वीकार कर दी गई है, और 'स्थिर' स्वयं नहीं है। मैंने कभी नहीं सोचा था कि यह इस तरह होगा। बेशक, यह वास्तव में एक स्थिर नहीं है जो मुझे लगता है।
टोनी एननिस

@TonyEnnis - यह इस बात पर निर्भर करता है कि आप वास्तव में स्थिर हैं। यह वास्तव में इस अर्थ में निरंतर है कि यह कार्यक्रम के निष्पादन के दौरान नहीं बदलेगा (modulo a couple of quibbles)। लेकिन यह सभी निष्पादन के लिए समान नहीं है।
स्टीफन सी

17

आप इस उदाहरण में एक एनम का उपयोग कर सकते हैं:

public class MainClass {
enum Choice { Choice1, Choice2, Choice3 }
public static void main(String[] args) {
Choice ch = Choice.Choice1;

switch(ch) {
  case Choice1:
    System.out.println("Choice1 selected");
    break;
 case Choice2:
   System.out.println("Choice2 selected");
   break;
 case Choice3:
   System.out.println("Choice3 selected");
   break;
    }
  }
}

स्रोत: एनम के साथ स्विच स्टेटमेंट


नमस्ते, मुझे अभी भी इस तरह से एनम का उपयोग करने में समस्या हो रही है: <br/> enum Codes { CODE_A(1), CODE_B(2); private mCode; Codes(int i) { mCode = i; } public int code() { return mCode; } }<br/> जब मैं स्विच में एनम का उपयोग करने का प्रयास करता हूं तो मुझे वही त्रुटि मिलती है ... <br/> switch(field) { case Codes.CODE_A.code() : // do stuffs.. ; } <br/> समस्या को हल करना संभव है?
शाओलिन

1
@stiga - आप केवल एनम इंस्टेंस पर ही स्विच कर सकते हैं। एनम उदाहरणों पर एक विधि कहकर लौटे कुछ मूल्य पर नहीं।
स्टीफन सी

3

यह उत्तर दिया गया था कि उम्र पहले और शायद प्रासंगिक नहीं है, लेकिन सिर्फ मामले में। जब मुझे इस मुद्दे का सामना करना पड़ा, तो मैंने ifइसके बजाय बस एक बयान का इस्तेमाल किया switch, इससे त्रुटि हल हो गई। यह निश्चित रूप से एक समाधान है और शायद "सही" समाधान नहीं है, लेकिन मेरे मामले में यह पर्याप्त था।


4
यह एक समाधान है और सवाल का जवाब नहीं है
जे डो

मुझे यहाँ वोट क्यों कम मिलते हैं? यह एक वैध वर्कअराउंड है
समीर मुराद

2
शायद इसलिए कि यह एक IF स्टेटमेंट है जिसे हम विशेष रूप से स्विच से बचने की कोशिश कर रहे हैं
डीन वाइल्ड

1
मैंने वोट दिया क्योंकि समस्या का समाधान करने के लिए यहाँ "कैसे" नहीं है, लेकिन समस्या "" क्यों हुई। मुझे लगता है कि आपका उत्तर संदर्भ से बाहर है। यदि आप पूर्णतावादी हैं, तो आपको यह महसूस करना चाहिए कि switchआम तौर पर लंबे समय से अधिक तेजी से होता है if-else, क्योंकि switchकेवल एक बार स्थिति की जांच करें , जबकि if-elseआपको सही खोजने से पहले सभी स्थिति की जांच करने की आवश्यकता हो सकती है ।
क्रिश्चियन लिम

0

कभी-कभी स्विच चर भी उदाहरण के लिए उस त्रुटि को बना सकता है:

switch(view.getTag()) {//which is an Object type

   case 0://will give compiler error that says Constant expression required

   //...
}

हल करने के लिए आपको चर को इंट (इस मामले में) डालना चाहिए। इसलिए:

switch((int)view.getTag()) {//will be int

   case 0: //No Error

   //...
}

0

कुछ ऐसा करते हुए Android में यह त्रुटि हुई:

 roleSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {

            switch (parent.getItemAtPosition(position)) {
                case ADMIN_CONSTANT: //Threw the error

            }

एक निरंतर घोषणा के बावजूद:

public static final String ADMIN_CONSTANT= "Admin";

मैंने इस पर अपना कोड बदलकर समस्या का समाधान किया:

roleSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {

            String selectedItem = String.valueOf(parent.getItemAtPosition(position));
            switch (selectedItem) {
                case ADMIN_CONSTANT:

            }

0

मेरे मामले में, मुझे यह अपवाद मिल रहा था क्योंकि

switch (tipoWebServ) {
                            case VariablesKmDialog.OBTENER_KM:
                                resultObtenerKm(result);
                                break;
                            case var.MODIFICAR_KM:
                                resultModificarKm(result);
                                break;
                        }

दूसरे मामले में मैं उदाहरण से निरंतर फोन कर रहा था, var.MODIFICAR_KM:लेकिन मुझे VariablesKmDialog.OBTENER_KMकक्षा से सीधे उपयोग करना चाहिए ।


0

यदि आप इसे स्विच केस में उपयोग कर रहे हैं तो आपको स्विच में उस मान को प्लग करने से पहले ही एनम का प्रकार प्राप्त करना होगा। उदाहरण के लिए :

SomeEnum someEnum = SomeEnum.values ​​() [1];

switch (someEnum) {
            case GRAPES:
            case BANANA: ...

और एनम की तरह है:

public enum SomeEnum {

    GRAPES("Grapes", 0),
    BANANA("Banana", 1),

    private String typeName;
    private int typeId;

    SomeEnum(String typeName, int typeId){
        this.typeName = typeName;
        this.typeId = typeId;
    }
}

0

नीचे दिया गया कोड स्व-व्याख्यात्मक है, हम एक स्विच केस के साथ एनम का उपयोग कर सकते हैं:

/**
 *
 */
enum ClassNames {
    STRING(String.class, String.class.getSimpleName()),
    BOOLEAN(Boolean.class, Boolean.class.getSimpleName()),
    INTEGER(Integer.class, Integer.class.getSimpleName()),
    LONG(Long.class, Long.class.getSimpleName());
    private Class typeName;
    private String simpleName;
    ClassNames(Class typeName, String simpleName){
        this.typeName = typeName;
        this.simpleName = simpleName;
    }
}

एनम से वर्ग मूल्यों के आधार पर मैप किया जा सकता है:

 switch (ClassNames.valueOf(clazz.getSimpleName())) {
        case STRING:
            String castValue = (String) keyValue;
            break;
        case BOOLEAN:
            break;
        case Integer:
            break;
        case LONG:
            break;
        default:
            isValid = false;

    }

आशा करता हूँ की ये काम करेगा :)


0

मैं निम्नलिखित तरीके का उपयोग करने की सलाह देता हूं:

public enum Animal {
    DOG("dog"), TIGER("tiger"), LION("lion");
    private final String name;

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


public class DemoSwitchUsage {

     private String getAnimal(String name) {
         Animal animalName = Animal.valueOf(name);
         switch(animalName) {
         case DOG:
             // write the code required.
             break;
         case LION:
             // Write the code required.
             break;
         default:
             break;
         }
     }
}

मुझे लगता है कि enum में निम्नलिखित कंस्ट्रक्टर होना चाहिए: private Animal(String name) { this.name = name; }
user1364368

-1

मैं तुम्हें enums का उपयोग करने की सलाह देता हूं :)

इसकी जांच करें:

public enum Foo 
{
    BAR("bar"),
    BAZ("baz"),
    BAM("bam");

    private final String description;

    private Foo(String description)
    {
        this.description = description;
    }

    public String getDescription()
    {
        return description;
    }
}

तो आप इसे इस तरह से उपयोग कर सकते हैं:

System.out.println(Foo.BAR.getDescription());

@djangofan आप किस कोड पर अपना कोड चला रहे हैं?
एवर्टन

मैंने JDK 1.7.0_74 का उपयोग IntelliJ-IDEA 14 के साथ
djangofan

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