अपवाद या त्रुटि कोड के लिए कन्वेंशन


118

कल मैं एक सहकर्मी के साथ एक गरमागरम बहस कर रहा था कि पसंदीदा त्रुटि रिपोर्टिंग विधि क्या होगी। मुख्य रूप से हम अनुप्रयोग परतों या मॉड्यूल के बीच त्रुटियों की रिपोर्ट करने के लिए अपवाद या त्रुटि कोड के उपयोग पर चर्चा कर रहे थे।

यदि आप अपवाद फेंकते हैं या त्रुटि रिपोर्टिंग के लिए त्रुटि कोड वापस करने के लिए क्या नियम का उपयोग करते हैं?

जवाबों:


81

उच्च-स्तरीय सामान में, अपवाद; निम्न स्तर के सामान में, त्रुटि कोड।

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

यदि, हालांकि, मैं एक कोड कोड लिख रहा हूं जिसे मुझे हर संभव स्थिति में व्यवहार का पता होना चाहिए , तो मुझे त्रुटि कोड चाहिए। अन्यथा मुझे हर अपवाद को जानना होगा जो मेरे कार्य में हर पंक्ति से पता चल सकता है कि यह क्या करेगा ( यह कैसे एक ट्रिक है इसका अंदाजा लगाने के लिए एक एयरलाइन ग्राउंडेड पढ़ें )। यह कोड लिखने के लिए थकाऊ और कठिन है जो हर स्थिति (दुखी लोगों सहित) के लिए उचित रूप से प्रतिक्रिया करता है, लेकिन ऐसा इसलिए है क्योंकि त्रुटि रहित कोड लिखना कठिन और कठिन है, इसलिए नहीं कि आप त्रुटि कोड पारित कर रहे हैं।

रेमंड चेन और जोएल दोनों ने हर चीज के अपवाद का उपयोग करने के खिलाफ कुछ स्पष्ट तर्क दिए हैं।


5
+1 यह इंगित करने के लिए कि त्रुटि से निपटने की रणनीति के संदर्भ में कुछ करना है।
alx9r

2
@ टॉम, अच्छे अंक, लेकिन अपवादों को पकड़े जाने की गारंटी है। हम यह कैसे सुनिश्चित करते हैं कि गलतियों के कारण त्रुटि कोड पकड़े गए और चुपचाप अनदेखा नहीं किया गया?
पचेरियर

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

3
C ++ 17 उस nodiscardविशेषता का परिचय देता है जो संकलक चेतावनी देगा यदि किसी फ़ंक्शन का रिटर्न मान संग्रहीत नहीं है। भूले हुए त्रुटि कोड की जाँच को पकड़ने में थोड़ी मदद करता है। उदाहरण: Godbolt.org/g/6i6E0B
Zitrax

5
@ एस्लेइजा की टिप्पणी यहाँ बिंदु पर है। यहां अपवादों के खिलाफ तर्क एक काल्पनिक त्रुटि-कोड-आधारित एपीआई लेता है, जहां सभी त्रुटि कोड दस्तावेज होते हैं और एक काल्पनिक प्रोग्रामर जो प्रलेखन पढ़ता है, उसके आवेदन में तार्किक रूप से संभव सभी त्रुटि मामलों की पहचान करता है, और उनमें से प्रत्येक को संभालने के लिए कोड लिखता है। , फिर उस परिदृश्य की तुलना एक काल्पनिक अपवाद-आधारित एपीआई और प्रोग्रामर से की जाती है, जहां किसी कारण से उन चरणों में से एक गलत हो जाता है ... भले ही अपवाद-आधारित एपीआई में उन सभी चरणों को प्राप्त करना समान रूप से आसान (यकीनन आसान ) हो।
मार्क एमी

62

मैं आम तौर पर अपवादों को पसंद करता हूं, क्योंकि उनके पास अधिक प्रासंगिक जानकारी होती है और स्पष्ट रूप से प्रोग्रामर को त्रुटि (जब सही तरीके से उपयोग की जाती है) को स्पष्ट रूप से बता सकते हैं।

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

संक्षेप में, मैं लगभग सभी स्थितियों में त्रुटि कोड पर अपवाद पसंद करता हूं।


4
"त्रुटि कोड अपवादों की तुलना में अधिक हल्के होते हैं" इस बात पर निर्भर करता है कि आप क्या मापते हैं और आप कैसे मापते हैं। अपवाद-आधारित API दिखाने वाले परीक्षणों के साथ आना बहुत आसान है, जो बहुत तेज़ हो सकते हैं।
मूइंग डक

1
@smink, अच्छे अंक, लेकिन हम अपवादों के ओवरहेड को कैसे संबोधित करते हैं? त्रुटि कोड केवल हल्के वजन वाले नहीं हैं, वे मूल रूप से भारहीन हैं ; अपवाद केवल मध्यम-वजन नहीं हैं, वे भारी- वजन वाली वस्तुएं हैं जिनमें स्टैक जानकारी और मिसक सामान हैं जो हम वैसे भी उपयोग नहीं करते हैं।
पचेरियर

3
@ स्पेसर: आप केवल उन परीक्षणों पर विचार कर रहे हैं, जहां अपवाद फेंके गए हैं। आप 100% सही हैं कि C ++ अपवाद फेंकना त्रुटि कोड को वापस करने की तुलना में काफी धीमा है। हाथ नीचे करो, कोई बहस नहीं। हम कहाँ हैं भिन्न होते हैं, कोड के अन्य 99.999% है। अपवादों के साथ, हम बनाने, प्रत्येक कथन के बीच त्रुटि कोड रिटर्न की जांच करने की जरूरत नहीं है कि कोड कुछ 1-50% तेजी से (या नहीं, अपने संकलक के आधार पर)। जिसका अर्थ है कि पूर्ण कोड तेजी से या धीमा हो सकता है, पूरी तरह से इस बात पर निर्भर करता है कि कोड कैसे लिखा गया है और कितनी बार अपवादों को फेंका गया है।
मिंग डक

1
@Pacerier: इस कृत्रिम परीक्षण के साथ, मैंने अभी लिखा, अपवाद आधारित कोड MSVC और क्लैंग में त्रुटि कोड जितना तेज़ है, हालांकि GCC नहीं: coliru.stacked-croched.com/a/e81694e5508945b (सबसे नीचे स्थित)। ऐसा प्रतीत होता है कि GCC के झंडे जो मैंने उपयोग किए थे वे अन्य संकलक की तुलना में असामान्य रूप से धीमे अपवाद थे। मैं पक्षपाती हूं, इसलिए कृपया मेरे परीक्षण की आलोचना करें, और दूसरे संस्करण की कोशिश करने के लिए स्वतंत्र महसूस करें।
मूविंग डक

4
@Mooing Duck, यदि आपने एक ही समय में त्रुटि कोड और अपवाद दोनों का परीक्षण किया है, तो आपके पास अपवाद सक्षम होना चाहिए। यदि ऐसा है, तो आपके परिणाम यह सुझाव देंगे कि ओवरहेड से निपटने के साथ त्रुटि कोड का उपयोग करना केवल अपवादों का उपयोग करने की तुलना में कोई धीमा नहीं है। त्रुटि कोड परीक्षणों को सार्थक परिणाम प्राप्त करने के लिए अक्षम किए गए अपवादों के साथ निष्पादित करने की आवश्यकता होगी।
मिका हराहिल्लतुनेन

24

मुझे अपवाद पसंद हैं क्योंकि

  • वे तर्क के प्रवाह को बाधित करते हैं
  • वे वर्ग पदानुक्रम से लाभ उठाते हैं जो अधिक सुविधाएँ / कार्यक्षमता प्रदान करता है
  • जब ठीक से उपयोग की जाने वाली त्रुटियों की एक विस्तृत श्रृंखला का प्रतिनिधित्व कर सकते हैं (जैसे एक InvalidMethodCallException भी एक LogicException है, दोनों तब होते हैं जब आपके कोड में एक बग होता है जो रनटाइम से पहले पता लगाने योग्य होना चाहिए), और
  • वे त्रुटि को बढ़ाने के लिए इस्तेमाल किया जा सकता है (यानी एक FileReadException वर्ग परिभाषा में यह जाँचने के लिए कोड हो सकता है कि क्या फ़ाइल मौजूद है, या बंद है, आदि)

2
आपका चौथा बिंदु एक उचित नहीं है: एक त्रुटि स्थिति जब एक वस्तु में परिवर्तित हो जाती है, तो यह जांचने के लिए कोड भी हो सकता है कि क्या फ़ाइल मौजूद है, या बंद है, आदि। यह बस stackoverflow.com/a/3157182/632951 की
पचेरियर

1
"वे तर्क के प्रवाह को बाधित करते हैं"। अपवादों का प्रभाव कम या ज्यादा होता हैgoto
पेटेरकुला

22

त्रुटि कोड को आपके कार्यों के कॉलर्स द्वारा अनदेखा किया जा सकता है (और अक्सर होता है!)। अपवाद कम से कम उन्हें किसी तरह से त्रुटि से निपटने के लिए मजबूर करते हैं। भले ही इससे निपटने के उनके संस्करण में एक खाली कैच हैंडलर (आह) हो।


17

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

यहाँ दो तकनीकों की चर्चा, तुलना और विरोधाभास है:

इसमें कुछ अच्छे लिंक हैं जो आपको आगे पढ़ने के लिए दे सकते हैं।


16

मैं दो मॉडलों को कभी नहीं मिलाऊंगा ... एक से दूसरे में बदलना बहुत मुश्किल है क्योंकि आप स्टैक के एक हिस्से से चलते हैं, जो त्रुटि कोड का उपयोग कर रहा है, एक उच्च टुकड़ा जो अपवादों का उपयोग कर रहा है।

अपवाद "ऐसी किसी भी चीज़ के लिए हैं, जो आपके द्वारा किए गए कार्य को करने से विधि या उप-प्रक्रिया को रोकती या रोकती है" ... अनियमितताओं या असामान्य परिस्थितियों, या सिस्टम की स्थिति, आदि के बारे में संदेश वापस पारित करने के लिए नहीं। वापसी मान या रेफ का उपयोग करें। (या बाहर) उसके लिए पैरामीटर।

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

Employee EmpOfMonth = GetEmployeeOfTheMonth();

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

Employee EmpOfMonth; 
if (getEmployeeOfTheMonth(ref EmpOfMonth) == ERROR)
    // code to Handle the error here

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


बहुत बढ़िया जवाब! बस समय में बॉक्स समाधान से बाहर!
क्रिश्चियन ई।

11

अतीत में मैं एररकोड कैंप में शामिल हुआ था (बहुत सी प्रोग्रामिंग की थी)। लेकिन अब मैंने रोशनी देखी है।

हाँ अपवाद सिस्टम पर थोड़ा बोझ हैं। लेकिन वे कोड को सरल बनाते हैं, त्रुटियों की संख्या (और डब्ल्यूटीएफ) को कम करते हैं।

इसलिए अपवाद का उपयोग करें, लेकिन उन्हें बुद्धिमान का उपयोग करें। और वे आपके दोस्त होंगे।

अलग नोट के रूप में। मैंने दस्तावेज़ को सीखा है कि किस विधि द्वारा अपवाद को फेंका जा सकता है। दुर्भाग्य से अधिकांश भाषाओं द्वारा इसकी आवश्यकता नहीं है। लेकिन यह सही स्तर पर सही अपवादों को संभालने की संभावना को बढ़ाता है।


1
yap C हम सभी में कुछ आदतों को छोड़ देता है;)
जॉर्ज

11

ऐसी कुछ स्थितियाँ हो सकती हैं, जहाँ साफ, स्पष्ट, सही तरीके से अपवादों का उपयोग करना बोझिल हो जाता है, लेकिन अधिकांश समय के अपवाद स्पष्ट पसंद होते हैं। त्रुटि कोड पर सबसे बड़ा लाभ अपवाद हैंडलिंग यह है कि यह निष्पादन के प्रवाह को बदलता है, जो दो कारणों से महत्वपूर्ण है।

जब कोई अपवाद होता है, तो एप्लिकेशन अब 'सामान्य' निष्पादन पथ का अनुसरण नहीं करता है। पहला कारण यह है कि यह इतना महत्वपूर्ण है कि जब तक कि कोड के लेखक अच्छी तरह से और सही मायने में खराब होने के अपने तरीके से बाहर नहीं निकलते हैं, तब तक कार्यक्रम रुक जाएगा और अप्रत्याशित चीजें करना जारी नहीं रखेगा। यदि एक त्रुटि कोड की जाँच नहीं होती है और एक खराब त्रुटि कोड के जवाब में उचित कार्रवाई नहीं की जाती है, तो कार्यक्रम यह करता रहेगा कि वह क्या कर रहा है और कौन जानता है कि उस कार्रवाई का परिणाम क्या होगा। वहाँ बहुत सारी स्थितियाँ हैं जहाँ कार्यक्रम होने से 'जो भी हो' बहुत महंगा हो सकता है। एक कार्यक्रम पर विचार करें जो एक कंपनी द्वारा बेचे जाने वाले विभिन्न वित्तीय साधनों के लिए प्रदर्शन जानकारी प्राप्त करता है, और उस जानकारी को दलालों / थोक विक्रेताओं तक पहुंचाता है। अगर कुछ गलत होता है और कार्यक्रम चलता रहता है, यह दलालों और थोक विक्रेताओं के लिए गलत प्रदर्शन डेटा शिप कर सकता है। मैं किसी और के बारे में नहीं जानता, लेकिन मैं यह बताना नहीं चाहता कि वीपीएस कार्यालय में बैठा व्यक्ति यह बताता है कि मेरे कोड के कारण कंपनी को 7-आंकड़े के लायक जुर्माना मिल सकता है। ग्राहकों को एक त्रुटि संदेश देना आम तौर पर गलत डेटा देने के लिए बेहतर होता है जो 'वास्तविक' दिख सकता है, और बाद की स्थिति त्रुटि कोड जैसे बहुत कम आक्रामक दृष्टिकोण के साथ चलना आसान है।

दूसरा कारण जो मुझे अपवादों को पसंद है और सामान्य निष्पादन को तोड़ना है, वह यह है कि यह बहुत आसान है, 'सामान्य चीजें हो रही हैं' तर्क 'कुछ गलत हो गया तर्क' से अलग है। मुझे य:

try {
    // Normal things are happening logic
catch (// A problem) {
    // Something went wrong logic
}

... इस के लिए बेहतर है:

// Some normal stuff logic
if (errorCode means error) {
    // Some stuff went wrong logic
}
// Some normal stuff logic
if (errorCode means error) {
    // Some stuff went wrong logic
}
// Some normal stuff logic
if (errorCode means error) {
    // Some stuff went wrong logic
}

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


8

आपको दोनों का उपयोग करना चाहिए। बात यह तय करने की है कि हर एक का उपयोग कब करना है

वहाँ एक हैं कुछ परिदृश्यों जहां अपवाद स्पष्ट पसंद कर रहे हैं :

  1. कुछ स्थितियों में आप त्रुटि कोड के साथ कुछ भी नहीं कर सकते हैं , और आपको कॉल स्टैक में ऊपरी स्तर पर इसे संभालने की आवश्यकता है , आमतौर पर बस त्रुटि लॉग करें, उपयोगकर्ता को कुछ प्रदर्शित करें या प्रोग्राम को बंद करें। इन मामलों में, त्रुटि कोडों को आपको त्रुटि कोडों को मैन्युअल रूप से स्तर से ऊपर करना होगा, जो स्पष्ट रूप से अपवादों के साथ करना बहुत आसान है। मुद्दा यह है कि यह अप्रत्याशित और असहनीय स्थितियों के लिए है।

  2. फिर भी स्थिति 1 के बारे में (जहां कुछ अप्रत्याशित और अनहोनी होती है, आप इसे लॉग इन करने के लिए नहीं चाहते हैं), अपवाद सहायक हो सकते हैं क्योंकि आप प्रासंगिक जानकारी जोड़ सकते हैं । उदाहरण के लिए यदि मुझे अपने निचले-स्तर के डेटा सहायकों में SqlException मिलती है, तो मैं उस त्रुटि को निम्न-स्तर में पकड़ना चाहूँगा (जहाँ मुझे SQL कमांड पता है कि त्रुटि हुई थी) तो मैं उस जानकारी को पकड़ सकता हूँ और अतिरिक्त जानकारी के साथ पुन: विचार कर सकता हूँ । कृपया यहां जादू शब्द पर ध्यान दें: रीथ्रो, और निगल नहींअपवाद से निपटने का पहला नियम: अपवादों को न निगलें । इसके अलावा, ध्यान दें कि मेरे आंतरिक कैच को कुछ भी लॉग इन करने की आवश्यकता नहीं है क्योंकि बाहरी कैच में पूरे स्टैक ट्रेस होंगे और इसे लॉग कर सकते हैं।

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

    एक उदाहरण लेन-देन ब्लॉक के अंदर एसक्यूएल स्टेटमेंट का एक क्रम होगा। फिर से, यह एक "असहनीय" स्थिति भी है, भले ही आप इसे जल्दी पकड़ने का फैसला करें (इसे स्थानीय रूप से ऊपर तक बुदबुदाने के बजाय इलाज करें) यह अभी भी एक घातक स्थिति है जहां से सबसे अच्छा परिणाम सब कुछ खत्म करना है या कम से कम एक बड़ा गर्भपात करना है। प्रक्रिया का हिस्सा।
    (*) यह उस तरह है जैसे on error gotoहमने पुराने Visual Basic में उपयोग किया था

  4. कंस्ट्रक्टर में आप केवल अपवाद फेंक सकते हैं।

यह कहते हुए कि, अन्य सभी स्थितियों में, जहाँ आप कुछ जानकारी लौटा रहे हैं, जिस पर कॉलर CAN / SHOULD कुछ कार्रवाई कर सकता है , रिटर्न कोड का उपयोग करना शायद एक बेहतर विकल्प है। इसमें सभी अपेक्षित "त्रुटियां" शामिल हैं , क्योंकि शायद उन्हें तत्काल कॉलर द्वारा नियंत्रित किया जाना चाहिए, और स्टैक में बहुत अधिक स्तर तक बुदबुदाए जाने की आवश्यकता नहीं होगी।

बेशक अपवादों के रूप में अपेक्षित त्रुटियों का इलाज करना हमेशा संभव होता है, और फिर तुरंत एक स्तर ऊपर पकड़ना, और कोशिश की कैच में कोड की हर पंक्ति को शामिल करना और प्रत्येक संभावित त्रुटि के लिए कार्रवाई करना भी संभव है। IMO, यह खराब डिज़ाइन है, न केवल इसलिए क्योंकि यह बहुत अधिक क्रिया है, बल्कि विशेष रूप से क्योंकि संभावित अपवाद जिन्हें फेंका जा सकता है, स्रोत कोड को पढ़े बिना स्पष्ट नहीं हैं - और अपवादों को किसी भी गहरी विधि से फेंक दिया जा सकता है, जिससे अदृश्य गोटो बन सकता है । वे कई अदृश्य निकास बिंदु बनाकर कोड संरचना को तोड़ते हैं जो कोड को पढ़ने और निरीक्षण करने के लिए कठिन बनाते हैं। दूसरे शब्दों में, आपको प्रवाह-नियंत्रण के रूप में अपवादों का उपयोग कभी नहीं करना चाहिए, क्योंकि दूसरों को समझना और बनाए रखना कठिन होगा। परीक्षण के लिए सभी संभावित कोड प्रवाह को समझना और भी मुश्किल हो सकता है।
फिर से: सही सफाई / निपटान के लिए आप कुछ भी पकड़े बिना कोशिश अंत में उपयोग कर सकते हैं

रिटर्न कोड के बारे में सबसे लोकप्रिय आलोचना यह है कि "कोई त्रुटि कोड को अनदेखा कर सकता है, लेकिन उसी अर्थ में कोई व्यक्ति अपवादों को भी निगल सकता है। खराब अपवाद हैंडलिंग दोनों तरीकों में आसान है। लेकिन अच्छा त्रुटि-कोड आधारित कार्यक्रम लिखना अभी भी बहुत आसान है। अपवाद-आधारित कार्यक्रम लिखने की तुलना में । और अगर किसी भी कारण से सभी त्रुटियों (पुराने on error resume next) को अनदेखा करने का फैसला किया जाता है , तो आप आसानी से रिटर्न कोड के साथ ऐसा कर सकते हैं और आप बहुत सारे ट्राइ-कैटर बॉयलरप्लेट के बिना ऐसा नहीं कर सकते।

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

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

इसका सारांश प्रस्तुत करना:

  • जब मुझे अप्रत्याशित स्थिति होती है, तो मैं अपवादों का उपयोग करना पसंद करता हूं, जिसमें ऐसा करने के लिए बहुत कुछ नहीं है, और आमतौर पर हम कोड के एक बड़े ब्लॉक या यहां तक ​​कि पूरे ऑपरेशन या प्रोग्राम को रोकना चाहते हैं। यह पुराने की तरह है "त्रुटि गोटो पर"।

  • मुझे ऐसे रिटर्न कोड का उपयोग करना पसंद है, जब मुझे ऐसी स्थितियों की उम्मीद होती है जिसमें कॉलर कोड कुछ कार्रवाई कर सकता है / चाहिए। इसमें अधिकांश व्यावसायिक विधियां, एपीआई, मान्यताएं, आदि शामिल हैं।

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

जीओ के बारे में फिर भी, यह कई रिटर्न वैल्यूज की अनुमति देता है , जो कि रिटर्न कोड का उपयोग करने में बहुत मदद करता है, क्योंकि आप एक साथ एक त्रुटि और कुछ और लौटा सकते हैं। C # / Java पर हम यह प्राप्त कर सकते हैं कि मापदंडों के साथ, Tuples, या (मेरी पसंदीदा) Generics, जो कि enums के साथ मिलकर कॉलर को स्पष्ट त्रुटि कोड प्रदान कर सकती हैं:

public MethodResult<CreateOrderResultCodeEnum, Order> CreateOrder(CreateOrderOptions options)
{
    ....
    return MethodResult<CreateOrderResultCodeEnum>.CreateError(CreateOrderResultCodeEnum.NO_DELIVERY_AVAILABLE, "There is no delivery service in your area");

    ...
    return MethodResult<CreateOrderResultCodeEnum>.CreateSuccess(CreateOrderResultCodeEnum.SUCCESS, order);
}

var result = CreateOrder(options);
if (result.ResultCode == CreateOrderResultCodeEnum.OUT_OF_STOCK)
    // do something
else if (result.ResultCode == CreateOrderResultCodeEnum.SUCCESS)
    order = result.Entity; // etc...

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


4

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

अन्य सभी मामलों में, अपवाद संभवतः जाने का तरीका है।


4

मैं यहाँ धरने पर बैठा हो सकता हूँ, लेकिन ...

  1. यह भाषा पर निर्भर करता है।
  2. आप जो भी मॉडल चुनते हैं, उसके अनुरूप होना चाहिए कि आप इसका उपयोग कैसे करते हैं।

पायथन में, अपवादों का उपयोग मानक अभ्यास है, और मैं अपने स्वयं के अपवादों को परिभाषित करने में काफी खुश हूं। C में आपके पास बिल्कुल भी अपवाद नहीं है।

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

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


4

चूंकि मैं सी ++ के साथ काम करता हूं, और उन्हें उपयोग करने के लिए सुरक्षित बनाने के लिए RAII है, मैं अपवादों का उपयोग लगभग अनन्य रूप से करता हूं। यह सामान्य प्रोग्राम फ्लो से निपटने में त्रुटि को खींचता है और इरादे को अधिक स्पष्ट करता है।

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


3

विधि हस्ताक्षरों को आपसे संवाद करना चाहिए कि विधि क्या करती है। लंबी एररकोड की तरह कुछ = getErrorCode (); ठीक हो सकता है, लेकिन लंबी त्रुटिकोड = fetchRecord (); ये भ्रमित करता है।


3

मेरा दृष्टिकोण यह है कि हम एक ही समय में यानी अपवाद और त्रुटियों दोनों का उपयोग कर सकते हैं।

मैं कई प्रकार के अपवादों को परिभाषित करने के लिए उपयोग किया जाता हूं (उदा: DataValidationException या ProcessInterruptExcepion) और प्रत्येक अपवाद के अंदर प्रत्येक समस्या का अधिक विस्तृत वर्णन परिभाषित करता है।

जावा में एक सरल उदाहरण:

public class DataValidationException extends Exception {


    private DataValidation error;

    /**
     * 
     */
    DataValidationException(DataValidation dataValidation) {
        super();
        this.error = dataValidation;
    }


}

enum DataValidation{

    TOO_SMALL(1,"The input is too small"),

    TOO_LARGE(2,"The input is too large");


    private DataValidation(int code, String input) {
        this.input = input;
        this.code = code;
    }

    private String input;

    private int code;

}

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


2
erm ... throw new DataValidationException("The input is too small")? अपवादों के फायदों में से एक विस्तृत जानकारी के लिए अनुमति है।
इवा

2

अपवाद असाधारण परिस्थितियों के लिए हैं - अर्थात, जब वे कोड के सामान्य प्रवाह का हिस्सा नहीं होते हैं।

यह अपवादों और त्रुटि कोडों को मिलाने के लिए काफी वैध है, जहां त्रुटि कोड किसी चीज की स्थिति का प्रतिनिधित्व करते हैं, न कि कोड के रनिंग में त्रुटि के बजाय (जैसे कि चाइल्ड प्रक्रिया से रिटर्न कोड की जांच करना)।

लेकिन जब एक असाधारण परिस्थिति होती है तो मेरा मानना ​​है कि अपवाद सबसे अधिक अभिव्यंजक मॉडल हैं।

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

लेकिन दूसरी दिशा में जाने से, अपवादों का उपयोग करने से आप अपनी त्रुटि से निपटने के लिए उच्च स्तर के सार का निर्माण कर सकते हैं, जिससे आपका कोड और भी अधिक अभिव्यंजक और प्राकृतिक हो सकता है। मैं अत्यधिक इस उत्कृष्ट, अभी तक कम, C ++ विशेषज्ञ आंद्रेई अलेक्जेंड्रेस्कु के लेख को पढ़ने की सिफारिश करूंगा, जिसे वे कहते हैं, "प्रवर्तन": http://www.ddj.com/cpp/184403864 । यद्यपि यह एक C ++ आलेख है, जो सिद्धांत आम तौर पर लागू होते हैं, और मैंने एनफोर्समेंट कॉन्सेप्ट का अनुवाद C # में सफलतापूर्वक किया है।


2

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

SOA में, जहाँ विभिन्न मशीनों में विधियाँ कही जा सकती हैं, अपवादों को तार के ऊपर से पारित नहीं किया जा सकता है, इसके बजाय, हम नीचे दिए गए ढांचे के साथ सफलता / विफलता प्रतिक्रियाओं का उपयोग करते हैं (C #):

public class ServiceResponse
{
    public bool IsSuccess => string.IsNullOrEmpty(this.ErrorMessage);

    public string ErrorMessage { get; set; }
}

public class ServiceResponse<TResult> : ServiceResponse
{
    public TResult Result { get; set; }
}

और इस तरह का उपयोग करें:

public async Task<ServiceResponse<string>> GetUserName(Guid userId)
{
    var response = await this.GetUser(userId);
    if (!response.IsSuccess) return new ServiceResponse<string>
    {
        ErrorMessage = $"Failed to get user."
    };
    return new ServiceResponse<string>
    {
        Result = user.Name
    };
}

जब ये आपकी सेवा प्रतिक्रियाओं में लगातार उपयोग किए जाते हैं तो यह एप्लिकेशन में सफलता / असफलताओं से निपटने का एक बहुत अच्छा पैटर्न बनाता है। यह सेवाओं के साथ-साथ सेवाओं के भीतर async कॉल में आसान त्रुटि से निपटने की अनुमति देता है।


1

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

अमान्य बिंदुओं को लौटाया जा सकता है, जो (उदाहरण के लिए जावा में NullPointerException का कारण बनता है) स्वीकार्य नहीं है।

एक ही फ़ंक्शन के रिटर्न मान के रूप में कई अलग-अलग संख्यात्मक त्रुटि कोड (-1, -2) का उपयोग करना आमतौर पर खराब शैली है, क्योंकि ग्राहक "<0" के बजाय "== -1" चेक कर सकते हैं।

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

एक और बात पर विचार करना है जब एक टीम में काम करते हैं, जहां इस तरह का निर्णय लेने के लिए अल्ट्रावेल्डर्स के लिए एक स्पष्ट रेखा खींचना है। उदाहरण के लिए "उच्च-स्तरीय सामान के लिए अपवाद, निम्न-स्तरीय सामान के लिए त्रुटि कोड" बहुत व्यक्तिपरक है।

किसी भी मामले में, जहां एक से अधिक तुच्छ प्रकार की त्रुटि संभव है, स्रोत कोड को कभी भी त्रुटि कोड को वापस करने के लिए या इसे संभालने के लिए संख्यात्मक शाब्दिक का उपयोग नहीं करना चाहिए (रिटर्न -7, यदि x == -7 ...), लेकिन हमेशा एक नामित स्थिरांक (NO_SUCH_FOO लौटाएं, अगर x == NO_SUCH_FOO)।


1

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

उदाहरण के लिए, आप केवल अपवादों का उपयोग करने का निर्णय लेते हैं। लेकिन एक बार जब आप async इवेंट प्रोसेसिंग का उपयोग करने का निर्णय लेते हैं। इस स्थिति में त्रुटि से निपटने के लिए अपवादों का उपयोग करना बुरा है। लेकिन आवेदन में हर जगह त्रुटि कोड का उपयोग थकाऊ है।

इसलिए मेरी राय है कि अपवाद और त्रुटि कोड दोनों का एक साथ उपयोग करना सामान्य है।


0

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


0

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

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

एक और usecase मेरे बारे में सोच सकता है जब डेटा नेटवर्क पर यात्रा करता है। आपका दूरस्थ तरीका डेटा ट्रांसफर को कम करने के लिए अपवाद के बजाय सिर्फ त्रुटि कोड वापस कर सकता है।


0

मेरा सामान्य नियम है:

  • किसी फ़ंक्शन में केवल एक त्रुटि दिखाई दे सकती है: त्रुटि कोड (फ़ंक्शन के पैरामीटर के रूप में) का उपयोग करें
  • एक से अधिक विशिष्ट त्रुटि दिखाई दे सकती हैं: अपवाद फेंकें

-1

जब आपकी विधि संख्यात्मक मान के अलावा और कुछ भी देती है तो त्रुटि कोड भी काम नहीं करते ...


3
उम नहीं। Win32 GetLastError () प्रतिमान देखें। मैं इसका बचाव नहीं कर रहा हूं, सिर्फ यह कह रहा हूं कि आप गलत हैं।
टिम

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