2009-05-13 23 views
49

लोगों के लिए अपवाद फेंकने का सुझाव देने के लिए:
अपवाद फेंकने से मुझे संकलन-समय त्रुटि नहीं मिलती है, यह मुझे रनटाइम त्रुटि देता है। मुझे पता है कि मैं एक अपवाद फेंक सकता हूं, मैं रनटाइम के दौरान संकलन के दौरान मर जाऊंगा।जावा एनम्स और स्विच स्टेटमेंट्स - डिफ़ॉल्ट केस?

फर्स्ट-ऑफ, मैं ग्रहण 3.4 का उपयोग कर रहा हूं।

मेरे पास एक डेटा मॉडल है जिसमें एक मोड प्रॉपर्टी है जो एनम है।

enum Mode {on(...), off(...), standby(...); ...} 

मैं वर्तमान में इस मॉडल के एक दृश्य के लिए लिख रहा हूँ और मैं कोड

... 
switch(model.getMode()) { 
case on: 
    return getOnColor(); 
case off: 
    return getOffColor(); 
case standby: 
    return getStandbyColor(); 
} 
... 

है मैं एक त्रुटि हो रही है "यह पद्धति प्रकार java.awt.Color का एक परिणाम लौटना चाहिए" क्योंकि मैं फ़ंक्शन के अंत में कोई डिफ़ॉल्ट केस नहीं है और कोई वापसी xxx नहीं है। I उस मामले में एक संकलन त्रुटि चाहते हैं जहां कोई व्यक्ति enum (जैसे शटडाउन) में एक और प्रकार जोड़ता है, इसलिए मैं एक डिफ़ॉल्ट केस नहीं डालना चाहता जो एक AssertionError फेंकता है, क्योंकि यह एक संशोधित मोड के साथ संकलित होगा और नहीं रनटाइम तक एक त्रुटि के रूप में देखा जाना चाहिए।

मेरा प्रश्न यह है:
EclipseBuilder (और javac) क्यों नहीं पहचानता, कि इस स्विच सभी संभावनाओं को शामिल किया गया (या यह उनके कवर करता है?) और मुझे एक वापसी प्रकार की आवश्यकता होगी, के बारे में चेतावनी बंद करो। क्या कोई तरीका है जो मैं मोड में विधियों को जोड़ने के बिना कर सकता हूं?

विफल होने पर, स्विच स्टेटमेंट्स पर चेतावनी/त्रुटि का कोई विकल्प है जो सभी एनम के संभावित मूल्यों को कवर नहीं करता है?

संपादित करें: रोब: यह एक संकलन त्रुटि है। मैंने इसे javac के साथ संकलित करने का प्रयास किया और मुझे विधि के अंतिम} को लक्षित करने में "अनुपलब्ध वापसी कथन" त्रुटि मिल गई। ग्रहण विधि के शीर्ष पर त्रुटि को बस रखता है।

+0

त्रुटि एक IDE चेतावनी या एसी है ओंपिलर त्रुटि? यदि बाद वाला, तो आपके पास कुछ विकल्प हो सकते हैं। – Rob

+3

अगर कोई व्यक्ति enum बदलता है तो कोई त्रुटि चाहते हैं: चीजें चाहते हैं, लेकिन कभी-कभी लोग ऐसी चीजें चाहते हैं जो समझ में नहीं आते हैं। जावा जैसी भाषा के मामले में, जहां फ़ाइलों को स्वतंत्र रूप से संकलित किया जा सकता है, यह सुनिश्चित करने का कोई तरीका नहीं है कि जब आप नहीं देख रहे थे तो enum नहीं बदला था। – kdgregory

+2

@kdgregory - हालांकि, अगर enum बदल जाता है और recompiled हो जाता है, तो आपकी कक्षा को फिर से सम्मिलित किया जाना चाहिए क्योंकि यह enum पर निर्भर करता है। मुझे नहीं लगता कि "यह स्विच एनम के सभी उदाहरणों को कैसे संभालता है" कहने की क्षमता और एक नया उदाहरण जोड़ने के लिए enum परिवर्तन ... "इस पंक्ति से enum विधि blah कहते हैं" से अलग है और कोई बदल रहा है उस विधि के प्रकार हस्ताक्षर। निश्चित रूप से, जावा अब इसका समर्थन नहीं करता है, लेकिन यह हो सकता है, और मुझे नहीं लगता कि इसका कोई नकारात्मक प्रभाव कैसे होगा ... यह केवल चीजों को क्लीनर, डेवलपर्स के लिए आसान बना देगा। – RHSeeger

उत्तर

65

तुम हमेशा आगंतुक पैटर्न के साथ Enum इस्तेमाल कर सकते हैं:

public final class ModeColorVisitor implements ModeVisitor<Color> { 
    public Color visitOn() { 
     return getOnColor(); 
    } 

    public Color visitOff() { 
     return getOffColor(); 
    } 

    public Color visitStandby() { 
     return getStandbyColor(); 
    } 

} 

आप इसे इस रूप में उपयोग करेंगे::

enum Mode { 
    on { 
     public <E> E accept(ModeVisitor<E> visitor) { 
     return visitor.visitOn(); 
     } 
    }, 
    off { 
     public <E> E accept(ModeVisitor<E> visitor) { 
     return visitor.visitOff(); 
     } 
    }, 
    standby { 
     public <E> E accept(ModeVisitor<E> visitor) { 
     return visitor.visitStandby(); 
     } 
    } 

    public abstract <E> E accept(ModeVisitor<E> visitor); 

    public interface ModeVisitor<E> { 
     E visitOn(); 
     E visitOff(); 
     E visitStandby(); 
    } 
} 

तो आप निम्नलिखित की तरह कुछ लागू करेगा

return model.getMode().accept(new ModeColorVisitor()); 

यह बहुत अधिक वर्बोज़ है लेकिन यदि कोई नया enum घोषित किया गया था तो आपको तुरंत संकलन त्रुटि मिल जाएगी।

+2

यह चुना गया था क्योंकि यह वही करता है जो मुझे चाहिए/चाहता है। यह enum राज्य के आधार पर मनमाने ढंग से तर्क की अनुमति देता है, w/o की आवश्यकता होती है कि enum ट्रैक चीजें जो ट्रैक करने के लिए कोई समझ नहीं लेती हैं। – KitsuneYMG

+0

दुर्भाग्य से यह काम नहीं करता है अगर आप एनम कोड को नियंत्रित नहीं करते हैं (और इसे एक स्वीकार्य विधि नहीं दे सकते हैं)। –

2

एक डिफ़ॉल्ट मामला है कि एक अपवाद फेंकता बनाएँ:

throw new RuntimeExeption("this code should never be hit unless someone updated the enum") 

... और कहा कि काफी का वर्णन करता है क्यों ग्रहण शिकायत कर रहा है: जबकि अपने स्विच आज सभी enum मामलों को कवर कर सकते, किसी को एक मामले जोड़ सकते हैं और नहीं कर सकता कल recompile।

2

ईक्लीप्सबिल्डर क्यों नहीं पहचानता कि यह स्विच सभी संभावनाओं को कवर करता है (या यह उन्हें कवर करता है?) और रिटर्न प्रकार की आवश्यकता के बारे में मुझे चेतावनी देना बंद कर देता है। क्या कोई तरीका है जो मैं मोड में विधियों को जोड़ने के बिना कर सकता हूं?

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

व्यक्तिगत रूप से, मैं बस कुछ प्रकार का अपवाद फेंक दूंगा।

+2

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

+1

आप देखेंगे कि मैंने त्रुटि उत्पन्न करने के रूप में EclipseBuilder निर्दिष्ट किया है। साथ ही, अपवाद फेंकने से मुझे संकलन-समय त्रुटि नहीं मिलती है, यह मुझे रनटाइम त्रुटि देता है, जो कि मैं एम्स को प्रदान करना चाहता था (सी-एनम्स जैसे इंट्स का उपयोग करने की तुलना में)। – KitsuneYMG

+0

छोटे ज्ञात तथ्य: ग्रहण जेडीटी वास्तव में जावैक से अपने स्वयं के कंपाइलर सेपरेट को शामिल करता है। http://www.eclipse.org/jdt/core/index.php – bendin

6

मैं कहूंगा कि यह शायद इसलिए है क्योंकि मॉडल। गेटमोड() वापस शून्य हो सकता है।

+2

yup। enums refence प्रकार हैं। – bendin

+2

मैंने अभी चेक किया है। मैंने माना था कि सूर्य जानता था कि वे Enums के साथ कर रहे थे, लेकिन स्पष्ट रूप से आप एक enum प्रकार के लिए शून्य असाइन कर सकते हैं। जिसका ब्राइंडेड विचार था। इस पर ध्यान दिलाने के लिए धन्यवाद। – KitsuneYMG

+4

यह समझ में नहीं आता है। इससे वैसे भी एक NullPointerException की ओर ले जाएगा। आप "केस नल" – amarillion

0

के बाद से मैं सिर्फ टिप्पणी नहीं कर सकता ...

  1. हमेशा की तरह, हमेशा की तरह, हमेशा एक डिफ़ॉल्ट मामला है। आप आश्चर्यचकित होंगे कि "बार" यह कैसे मारा जाएगा (सी से जावा में कम, लेकिन फिर भी)।

  2. ऐसा कहकर, अगर मैं केवल अपने मामले में केवल चालू/बंद करना चाहता हूं तो क्या होगा। जावैक द्वारा आपकी अर्थपूर्ण प्रसंस्करण उस मुद्दे को ध्वजांकित करेगी।

+0

के लिए (2) आपके पास एक डिफ़ॉल्ट केस होगा जिसमें आप प्रबंधित नहीं कर रहे हैं। मुझे लगता है कि मुद्दा यह है कि वह पहले से ही हर enum को संभालने वाला है, इसलिए उसे संकलन के दौरान "कोई वापसी मूल्य" त्रुटि नहीं मिलनी चाहिए। –

2

आपकी समस्या यह है कि आप स्विच स्टेटमेंट को एक संकेतक के रूप में उपयोग करने का प्रयास कर रहे हैं कि आपका enum लॉक हो गया है।

तथ्य यह है कि 'स्विच' कथन और जावा कंपाइलर यह नहीं पहचान सकता कि आप अपने enum में अन्य विकल्पों की अनुमति नहीं देना चाहते हैं। तथ्य यह है कि आप केवल अपने enum में तीन विकल्प चाहते हैं स्विच स्विच के अपने डिज़ाइन से पूरी तरह से अलग है, जैसा कि दूसरों द्वारा नोट किया गया है हमेशा एक डिफ़ॉल्ट कथन होना चाहिए। (आपके मामले में इसे अपवाद फेंकना चाहिए, क्योंकि यह एक अनचाहे परिदृश्य है।)

आपको उदारता से टिप्पणियों के साथ अपने enum छिड़कना चाहिए ताकि हर कोई इसे छूने के लिए नहीं जानता है, और आपको अपने स्विच स्टेटमेंट को त्रुटियों को फेंकने के लिए ठीक करना चाहिए अपरिचित मामलों इस तरह आपने सभी अड्डों को कवर किया है।

संपादित

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

एनम और स्विच की आंतरिक कार्य पूरी तरह से अलग हैं और अनिश्चित रहना चाहिए।

9

मुझे नहीं पता कि आपको यह त्रुटि क्यों मिलती है, लेकिन यहां एक सुझाव है, आप एनम में रंग क्यों परिभाषित नहीं करते? फिर आप एक नए रंग को परिभाषित करने के लिए गलती से भूल नहीं सकते हैं।

उदाहरण के लिए:

import java.awt.Color; 

public class Test { 

    enum Mode 
    { 
     on (Color.BLACK), 
     off (Color.RED), 
     standby (Color.GREEN); 

     private final Color color; 
     Mode (Color aColor) { color = aColor; } 
     Color getColor() { return color; } 
    } 

    class Model 
    { 
     private Mode mode; 
     public Mode getMode() { return mode; } 
    } 

    private Model model; 

    public Color getColor() 
    { 
     return model.getMode().getColor(); 
    } 
} 

btw, तुलना के लिए यहाँ मूल मामले संकलक त्रुटि के साथ है। सेटिंग्स "Enum प्रकार लगातार स्विच में शामिल नहीं" त्रुटि स्तर के साथ -

import java.awt.Color; 
public class Test { 

    enum Mode {on, off, standby;} 

    class Model 
    { 
     private Mode mode; 
     public Mode getMode() { return mode; } 
    } 

    private Model model; 

    public Color getColor() 
    { 
     switch(model.getMode()) { 
     case on: 
      return Color.BLACK; 
     case off: 
      return Color.RED; 
     case standby: 
      return Color.GREEN; 
     } 
    } 
} 
56

आप ग्रहण में (> वरीयताओं विंडो) को सक्षम करने के लिए है।

विधि के अंत में अपवाद फेंको, लेकिन डिफ़ॉल्ट केस का उपयोग न करें।

public String method(Foo foo) 
    switch(foo) { 
    case x: return "x"; 
    case y: return "y"; 
    } 

    throw new IllegalArgumentException(); 
} 

अब अगर कोई नया मामला जोड़ता है, तो ग्रहण उसे बताएगा कि वह एक मामला खो रहा है। इसलिए जब तक आपके पास ऐसा करने के लिए वास्तव में अच्छे कारण नहीं हैं तब तक डिफ़ॉल्ट का उपयोग न करें।

+7

मैं आपको यह बताना चाहता था कि मैंने आपके बजाय अन्य उत्तर स्वीकार कर लिया है। आपका काम बहुत अच्छा है ... जब तक कि सभी लोग उस विकल्प सेट के साथ एक्लिस्पे का उपयोग करते हैं। मैंने जो जवाब चुना वह सभी जावा कंपाइलर्स के साथ काम करता है। अगर मैं आपको फिर से रेट कर सकता हूं तो मैं चाहता हूं। – KitsuneYMG

+1

टिप्पणी करने के लिए धन्यवाद, मुझे उम्मीद है कि आप मेरे संपादन के बाद इसे नोटिस करेंगे। मैं पहले मसौदे में सबसे महत्वपूर्ण हिस्सा शामिल करना भूल गया। मैं खुश हूं कि मैं मदद कर सका। – egaga

2

इस के लिए एक अच्छा तरीका है डिफ़ॉल्ट मामले जोड़ने के लिए कुछ त्रुटि मान, उदाहरण के लिए वापसी या अपवाद फेंक और JUnit साथ स्वचालित परीक्षण का उपयोग करने के लिए होगा:

@Test 
public void testEnum() { 
    for(Mode m : Mode.values() { 
    m.foobar(); // The switch is separated to a method 
    // If you want to check the return value, do it (or if there's an exception in the 
    // default part, that's enough) 
    } 
} 

जब आप स्वचालित गया परीक्षण, इस वसीयत उस foobar का ख्याल रखना सभी गणनाओं के लिए परिभाषित किया गया है।

0

आजकल (मूल प्रश्न के बाद इस जवाब लिखा है कई वर्षों), ग्रहण खिड़की पर विन्यास निम्नलिखित की अनुमति देता है -> वरीयताएँ -> जावा -> संकलक -> त्रुटि/चेतावनी -> संभावित प्रोग्रामिंग समस्याओं:

अधूरा स्विच मामलों

डिफ़ॉल्ट मामले मौजूद सिग्नल भले ही

संबंधित मुद्दे