c# - जावा या सी#में अपवाद प्रबंधन के लिए सर्वोत्तम अभ्यास




java exception (10)

मैं अपने आवेदन में अपवादों को संभालने का निर्णय ले रहा हूं।

अगर अपवादों के साथ मेरे मुद्दे 1 से आता है) एक दूरस्थ सेवा के माध्यम से डेटा तक पहुंचने या 2) एक JSON ऑब्जेक्ट deserializing। दुर्भाग्य से मैं इन कार्यों में से किसी एक के लिए सफलता की गारंटी नहीं दे सकता (नेटवर्क कनेक्शन में कटौती, विकृत जेएसओएन ऑब्जेक्ट जो मेरे नियंत्रण से बाहर है)।

नतीजतन, अगर मुझे अपवाद का सामना करना पड़ता है तो मैं इसे केवल फ़ंक्शन के भीतर पकड़ता हूं और कॉलर को FALSE लौटाता हूं। मेरा तर्क यह है कि सभी कॉलर वास्तव में परवाह करते हैं कि यदि कार्य सफल रहा, तो यह सफल क्यों नहीं था।

यहां एक सामान्य विधि के कुछ नमूना कोड (जावा में) है

public boolean doSomething(Object p_somthingToDoOn)
{
    boolean result = false;

    try{
        // if dirty object then clean
        doactualStuffOnObject(p_jsonObject);

        //assume success (no exception thrown)
        result = true;
    }
    catch(Exception Ex)
    {
        //don't care about exceptions
        Ex.printStackTrace();
    }
    return result;
}

मुझे लगता है कि यह दृष्टिकोण ठीक है, लेकिन मुझे यह जानकर उत्सुकता है कि अपवादों के प्रबंधन के लिए सर्वोत्तम प्रथाएं क्या हैं (क्या मुझे वास्तव में कॉल स्टैक तक अपवाद को बुलबुला करना चाहिए?)।

मुख्य प्रश्नों के सारांश में:

  1. क्या अपवादों को पकड़ना ठीक है, लेकिन उन्हें बुलबुला नहीं करना या औपचारिक रूप से सिस्टम को सूचित करना (या तो लॉग या उपयोगकर्ता के लिए अधिसूचना के माध्यम से)?
  2. उन अपवादों के लिए कौन सी सर्वोत्तम प्रथाएं हैं जिनके परिणामस्वरूप प्रयास / पकड़ ब्लॉक की आवश्यकता होती है?

अनुवर्ती / संपादित करें

सभी प्रतिक्रियाओं के लिए धन्यवाद, ऑनलाइन अपवाद प्रबंधन पर कुछ उत्कृष्ट स्रोत पाए गए:

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

इसके अतिरिक्त अत्यधिक प्रयास / कैच के माध्यम से कोड-रोट के लिए देखें या अपवाद नहीं दे रहे हैं (एक अपवाद सिस्टम को चेतावनी दे रहा है, और क्या चेतावनी दी जानी चाहिए?)।

इसके अलावा, यह m3rLinEz से एक सुंदर पसंद टिप्पणी है।

मैं एंडर्स हेजल्सबर्ग से सहमत हूं और आप सबसे अधिक कॉलर केवल देखभाल करते हैं यदि ऑपरेशन सफल है या नहीं।

इस टिप्पणी से अपवादों से निपटने के बारे में सोचने के लिए कुछ प्रश्न सामने आते हैं:

  • इस अपवाद को फेंकने का क्या मतलब है?
  • इसे संभालने के लिए यह कैसे समझ में आता है?
  • क्या कॉलर वास्तव में अपवाद के बारे में परवाह करता है या क्या कॉल पर सफल होने पर वे सिर्फ ख्याल रखते हैं?
  • एक संभावित अपवाद का प्रबंधन करने के लिए एक कॉलर मजबूर कर रहा है?
  • क्या आप भाषा की मूर्तियों का सम्मान कर रहे हैं?
    • क्या आपको वास्तव में बूलियन जैसे सफलता झंडे को वापस करने की ज़रूरत है? रिटर्निंग बूलियन (या एक इंट) जावा की तुलना में सी मानसिकता से अधिक है (जावा में आप केवल अपवाद को संभालेंगे) एक।
    • भाषा से जुड़े त्रुटि प्रबंधन संरचनाओं का पालन करें :)!

अपवाद त्रुटियां हैं जो सामान्य प्रोग्राम निष्पादन का हिस्सा नहीं हैं। आपके प्रोग्राम और उसके उपयोग (यानी एक शब्द प्रोसेसर बनाम हृदय मॉनीटर) के आधार पर आप अपवाद का सामना करते समय अलग-अलग चीजें करना चाहेंगे। मैंने कोड के साथ काम किया है जो सामान्य निष्पादन के हिस्से के रूप में अपवादों का उपयोग करता है और यह निश्चित रूप से एक कोड गंध है।

पूर्व।

try
{
   sendMessage();

   if(message == success)
   {
       doStuff();
   }
   else if(message == failed)
   {
       throw;
   }
}
catch(Exception)
{
    logAndRecover();
}

यह कोड मुझे बारफ बनाता है। आईएमओ आपको अपवादों से ठीक नहीं होना चाहिए जब तक कि यह एक महत्वपूर्ण कार्यक्रम न हो। यदि आपके फेंकने के अपवाद तो बुरी चीजें हो रही हैं।


आपको केवल उन अपवादों को पकड़ना चाहिए जिनसे आप निपट सकते हैं। उदाहरण के लिए, यदि आप किसी नेटवर्क पर पढ़ने और कनेक्शन के समय से निपटने के साथ काम कर रहे हैं और आपको अपवाद मिलता है तो आप पुनः प्रयास कर सकते हैं। हालांकि यदि आप किसी नेटवर्क पर पढ़ रहे हैं और इंडेक्सऑटऑफबाउंड अपवाद प्राप्त करते हैं, तो आप वास्तव में इसे संभाल नहीं सकते हैं क्योंकि आप नहीं करते हैं (ठीक है, इस मामले में आप नहीं जानते) इसका कारण क्या है। यदि आप झूठी या -1 या शून्य वापस करने जा रहे हैं, तो सुनिश्चित करें कि यह विशिष्ट अपवादों के लिए है। मैं एक पुस्तकालय नहीं चाहता हूं जिसका उपयोग मैं नेटवर्क पर झूठा लौटने का उपयोग कर रहा हूं, जब अपवाद फेंक दिया जाता है तो ढेर स्मृति से बाहर होता है।


कुछ विचारों के बाद और आपके कोड को देखते हुए मुझे लगता है कि आप बस एक बूलियन के रूप में अपवाद को पुनर्स्थापित कर रहे हैं। आप इस विधि को इस अपवाद को पास कर सकते हैं (आपको इसे पकड़ना भी नहीं है) और कॉलर में इसके साथ सौदा करें, क्योंकि यह वह जगह है जहां यह महत्वपूर्ण है। यदि अपवाद कॉलर को इस फ़ंक्शन को पुनः प्रयास करने का कारण बनता है, तो कॉलर अपवाद को पकड़ने वाला व्यक्ति होना चाहिए।

यह कभी-कभी ऐसा हो सकता है कि आप जिस अपवाद का सामना कर रहे हैं वह कॉलर को समझ में नहीं आता है (यानी यह नेटवर्क अपवाद है), इस मामले में आपको इसे डोमेन विशिष्ट अपवाद में लपेटना चाहिए।

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


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

अंगूठे के नियमों के रूप में, इन दिशानिर्देशों के आस-पास अपवाद हैंडलिंग कुछ विशेष क्रम में नहीं होना चाहिए:

  • रखरखाव के लिए, हमेशा अपवाद लॉग इन करें ताकि जब आप बग देखना शुरू कर दें, तो लॉग आपको उस स्थान पर इंगित करने में सहायता करेगा जो आपकी बग की संभावना है। printStackTrace() या इसकी पसंद कभी न छोड़ें, संभावना है कि आपके उपयोगकर्ताओं में से एक अंततः उन स्टैक निशानों में से एक प्राप्त करेगा, और इसमें शून्य ज्ञान होगा कि इसके साथ क्या किया जाए।
  • उन अपवादों को पकड़ें जिन्हें आप संभाल सकते हैं, और केवल उनको, और उन्हें संभालें , उन्हें केवल ढेर को फेंक न दें।
  • हमेशा एक विशिष्ट अपवाद वर्ग को पकड़ें, और आम तौर पर आपको कभी भी Exception पकड़ना नहीं चाहिए, आपको अन्यथा महत्वपूर्ण अपवादों को निगलने की संभावना है।
  • कभी नहीं (कभी) पकड़ Error !! , जिसका अर्थ है: Throwable एस को कभी भी Throwable क्योंकि Error एस उत्तरार्द्ध के उप-वर्ग हैं। Error ऐसी समस्याएं हैं जिन्हें आप कभी भी संभालने में सक्षम नहीं होंगे (उदाहरण के लिए OutOfMemory , या अन्य जेवीएम मुद्दे)

अपने विशिष्ट मामले के बारे में, सुनिश्चित करें कि आपकी विधि को कॉल करने वाले किसी भी ग्राहक को उचित वापसी मूल्य प्राप्त होगा। अगर कुछ विफल हो जाता है, तो बूलियन-रिटर्निंग विधि झूठी वापसी कर सकती है, लेकिन सुनिश्चित करें कि जिन स्थानों को आप कॉल करते हैं, वे इसे संभालने में सक्षम हैं।


मुझे जवाब के साथ थोड़ा देर हो सकती है लेकिन त्रुटि प्रबंधन कुछ ऐसा है जिसे हम हमेशा बदल सकते हैं और समय के साथ विकसित कर सकते हैं। यदि आप इस विषय के बारे में कुछ और पढ़ना चाहते हैं तो मैंने इसके बारे में अपने नए ब्लॉग में एक पोस्ट लिखा है। http://taoofdevelopment.wordpress.com

हैप्पी कोडिंग


मेरी रणनीति:

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

अगर फ़ंक्शन को कुछ वापस करना चाहिए तो अपवाद / त्रुटि वापस आती है, अन्यथा वापसी योग्य आइटम।

बूल के बजाय त्रुटि का वर्णन युक्त स्ट्रिंग को वापस किया जा सकता है।

कुछ भी लौटने से पहले हर मामले में त्रुटि लॉग करें।


मैं इस विषय पर एक और अच्छे स्रोत की सिफारिश करना चाहता हूं। जावा की जांच की गई अपवाद के विषय पर यह सी # और जावा, एंडर्स हेजल्सबर्ग और जेम्स गोस्लिंग के आविष्कारकों के साथ एक साक्षात्कार है।

विफलता और अपवाद

पृष्ठ के निचले भाग में भी बहुत अच्छे संसाधन हैं।

मैं एंडर्स हेजल्सबर्ग से सहमत हूं और आप सबसे अधिक कॉलर केवल देखभाल करते हैं यदि ऑपरेशन सफल है या नहीं।

बिल वेनर्स : आपने चेक अपवादों के संबंध में स्केलेबिलिटी और वर्जनिंग चिंताओं का उल्लेख किया है। क्या आप उन दो मुद्दों से क्या मतलब समझ सकते हैं?

एंडर्स हेजल्सबर्ग : चलिए संस्करण के साथ शुरू करते हैं, क्योंकि मुद्दों को वहां देखना बहुत आसान है। आइए मान लें कि मैं एक विधि foo बनाता हूं जो घोषणा करता है कि यह ए, बी, और सी अपवादों को फेंक देता है, मैं दो संस्करणों में, मैं सुविधाओं का एक समूह जोड़ना चाहता हूं, और अब foo अपवाद फेंक सकता है डी। यह मेरे लिए एक तोड़ने वाला बदलाव है उस विधि के फेंकने वाले खंड में डी जोड़ें, क्योंकि उस विधि का मौजूदा कॉलर लगभग निश्चित रूप से उस अपवाद को संभाल नहीं पाएगा।

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

बिल वेनेर्स : लेकिन क्या आप किसी भी मामले में अपने कोड को तोड़ने नहीं कर रहे हैं, यहां तक ​​कि बिना किसी अपवाद के भाषा में? यदि foo का नया संस्करण एक नया अपवाद फेंकने जा रहा है जिसे ग्राहकों को हैंडलिंग के बारे में सोचना चाहिए, तो क्या उनके कोड को इस तथ्य से तोड़ा नहीं गया है कि उन्होंने कोड को लिखते समय उस अपवाद की अपेक्षा नहीं की थी?

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

फेंकता खंड, कम से कम जिस तरह से इसे जावा में लागू किया गया है, आपको अपवादों को संभालने के लिए जरूरी नहीं है, लेकिन यदि आप उन्हें संभाल नहीं पाते हैं, तो यह आपको यह स्वीकार करने के लिए मजबूर करता है कि कौन से अपवाद पारित हो सकते हैं। यह आपको या तो घोषित अपवादों को पकड़ने या उन्हें अपने स्वयं के फेंकने वाले खंड में रखने की आवश्यकता है। इस आवश्यकता के आसपास काम करने के लिए, लोग हास्यास्पद चीजें करते हैं। उदाहरण के लिए, वे हर विधि को सजाते हैं, "अपवाद फेंकता है।" यह सिर्फ सुविधा को पूरी तरह से हरा देता है, और आपने प्रोग्रामर को और अधिक gobbledy gunk लिख दिया है। यह किसी की मदद नहीं करता है।

संपादित करें: कनवर्स्टियन पर अधिक जानकारी जोड़ा गया


यदि आप अपने उदाहरण में कोड पैटर्न का उपयोग करने जा रहे हैं, तो इसे TryDoSomething कहें, और केवल विशिष्ट अपवादों को पकड़ें।

नैदानिक ​​उद्देश्यों के लिए अपवाद लॉगिंग करते समय एक अपवाद फ़िल्टर का उपयोग करने पर भी विचार करें । वीबी के पास अपवाद फिल्टर के लिए भाषा समर्थन है। Greggm के ब्लॉग के लिंक में एक कार्यान्वयन है जिसका उपयोग सी # से किया जा सकता है। अपवाद फिल्टर में कैच और रीथ्रो पर डिबग्बिलिटी के लिए बेहतर गुण होते हैं। विशेष रूप से आप फ़िल्टर में समस्या को लॉग कर सकते हैं और अपवाद को प्रचारित करना जारी रख सकते हैं। यह विधि पूर्ण मूल ढेर रखने के लिए एक जेआईटी (जस्ट इन टाइम) डीबगर को जोड़ने की अनुमति देती है। एक उथल-पुथल उस बिंदु पर स्टैक को काट देता है जिसे इसे पुनर्स्थापित किया गया था।

जिन मामलों में TryXXXX समझ में आता है वे तब होते हैं जब आप किसी तृतीय पक्ष फ़ंक्शन को लपेट रहे होते हैं जो उन मामलों में फेंकता है जो वास्तव में असाधारण नहीं हैं, या फ़ंक्शन को कॉल किए बिना परीक्षण करना मुश्किल है। एक उदाहरण कुछ ऐसा होगा:

// throws NumberNotHexidecimalException
int ParseHexidecimal(string numberToParse); 

bool TryParseHexidecimal(string numberToParse, out int parsedInt)
{
     try
     {
         parsedInt = ParseHexidecimal(numberToParse);
         return true;
     }
     catch(NumberNotHexidecimalException ex)
     {
         parsedInt = 0;
         return false;
     }
     catch(Exception ex)
     {
         // Implement the error policy for unexpected exceptions:
         // log a callstack, assert if a debugger is attached etc.
         LogRetailAssert(ex);
         // rethrow the exception
         // The downside is that a JIT debugger will have the next
         // line as the place that threw the exception, rather than
         // the original location further down the stack.
         throw;
         // A better practice is to use an exception filter here.
         // see the link to Exception Filter Inject above
         // http://code.msdn.microsoft.com/ExceptionFilterInjct
     }
}

चाहे आप TryXXX जैसे पैटर्न का उपयोग करें या नहीं, एक स्टाइल प्रश्न है। सभी अपवादों को पकड़ने और उन्हें निगलने का सवाल शैली का मुद्दा नहीं है। सुनिश्चित करें कि अप्रत्याशित अपवादों को प्रसारित करने की अनुमति है!


यह आवेदन और स्थिति पर निर्भर करता है। यदि आप एक लाइब्रेरी घटक बनाते हैं, तो आपको अपवादों को बुलबुला करना चाहिए, हालांकि उन्हें आपके घटक के साथ प्रासंगिक होने के लिए लपेटा जाना चाहिए। उदाहरण के लिए यदि आप एक एक्सएमएल डेटाबेस बनाते हैं और मान लें कि आप अपने डेटा को स्टोर करने के लिए फाइल सिस्टम का उपयोग कर रहे हैं, और आप डेटा को सुरक्षित करने के लिए फ़ाइल सिस्टम अनुमतियों का उपयोग कर रहे हैं। आप एक FileIOAccessDenied अपवाद को बबल नहीं करना चाहते हैं क्योंकि यह आपके कार्यान्वयन को रिसाव करता है। इसके बजाय आप अपवाद लपेटेंगे और AccessDenied त्रुटि फेंक देंगे। यह विशेष रूप से सच है यदि आप घटक को तीसरे पक्ष को वितरित करते हैं।

जैसे कि अपवादों को निगलना ठीक है। यह आपके सिस्टम पर निर्भर करता है। यदि आपका एप्लिकेशन विफलता के मामलों को संभाल सकता है और उपयोगकर्ता को सूचित करने से कोई फायदा नहीं होता है कि यह क्यों विफल हुआ तो आगे बढ़ें, हालांकि मैं अत्यधिक अनुशंसा करता हूं कि आपका लॉग विफलता हो। मुझे हमेशा किसी समस्या का निवारण करने में मदद करने के लिए बुलाया जा रहा है और यह पता चला है कि वे अपवाद निगल रहे थे (या इसे बदलकर और आंतरिक अपवाद को सेट किए बिना एक नया फेंकना)।

आम तौर पर मैं निम्नलिखित नियमों का उपयोग करता हूं:

  1. मेरे घटकों और पुस्तकालयों में मैं केवल अपवाद पकड़ता हूं अगर मैं इसे संभालने का इरादा रखता हूं या इसके आधार पर कुछ करता हूं। या अगर मैं अपवाद में अतिरिक्त प्रासंगिक जानकारी प्रदान करना चाहता हूं।
  2. मैं आवेदन प्रविष्टि बिंदु, या उच्चतम स्तर पर एक सामान्य प्रयास पकड़ का उपयोग करें। अगर कोई अपवाद यहां आता है तो मैं इसे लॉग करता हूं और इसे असफल होने देता हूं। आदर्श रूप से अपवाद कभी यहां नहीं आना चाहिए।

मुझे निम्न कोड गंध होने के लिए मिलता है:

try
{
    //do something
}
catch(Exception)
{
   throw;
}

इस तरह के कोड कोई बिंदु नहीं है और शामिल नहीं किया जाना चाहिए।


यह मेरे लिए अजीब लगता है कि आप अपवादों को पकड़ना चाहते हैं और उन्हें त्रुटि कोड में बदलना चाहते हैं। आपको क्यों लगता है कि कॉलर अपवादों पर त्रुटि कोड पसंद करेगा जब बाद वाला जावा और सी # दोनों में डिफ़ॉल्ट होगा?

आपके प्रश्नों के लिए:

  1. आपको केवल उन अपवादों को पकड़ना चाहिए जिन्हें आप वास्तव में संभाल सकते हैं। बस अपवादों को पकड़ना ज्यादातर मामलों में करना सही नहीं है। कुछ अपवाद हैं (उदाहरण के लिए लॉगिंग और धागे के बीच अपवादों को मार्शल करना) लेकिन उन मामलों के लिए भी आपको अपवादों को फिर से उखाड़ना चाहिए।
  2. आपको निश्चित रूप से अपने कोड में बहुत से प्रयास / पकड़ने के बयान नहीं होना चाहिए। दोबारा, विचार केवल उन अपवादों को पकड़ना है जिन्हें आप संभाल सकते हैं। आप किसी भी अनचाहे अपवाद को अंतिम उपयोगकर्ता के लिए कुछ हद तक उपयोगी बनाने के लिए एक शीर्ष अपवाद हैंडलर शामिल कर सकते हैं लेकिन अन्यथा आपको हर संभव स्थान में प्रत्येक अपवाद को पकड़ने की कोशिश नहीं करनी चाहिए।






error-handling