आपको दोनों का उपयोग करना चाहिए। बात यह तय करने की है कि हर एक का उपयोग कब करना है ।
वहाँ एक हैं कुछ परिदृश्यों जहां अपवाद स्पष्ट पसंद कर रहे हैं :
कुछ स्थितियों में आप त्रुटि कोड के साथ कुछ भी नहीं कर सकते हैं , और आपको कॉल स्टैक में ऊपरी स्तर पर इसे संभालने की आवश्यकता है , आमतौर पर बस त्रुटि लॉग करें, उपयोगकर्ता को कुछ प्रदर्शित करें या प्रोग्राम को बंद करें। इन मामलों में, त्रुटि कोडों को आपको त्रुटि कोडों को मैन्युअल रूप से स्तर से ऊपर करना होगा, जो स्पष्ट रूप से अपवादों के साथ करना बहुत आसान है। मुद्दा यह है कि यह अप्रत्याशित और असहनीय स्थितियों के लिए है।
फिर भी स्थिति 1 के बारे में (जहां कुछ अप्रत्याशित और अनहोनी होती है, आप इसे लॉग इन करने के लिए नहीं चाहते हैं), अपवाद सहायक हो सकते हैं क्योंकि आप प्रासंगिक जानकारी जोड़ सकते हैं । उदाहरण के लिए यदि मुझे अपने निचले-स्तर के डेटा सहायकों में SqlException मिलती है, तो मैं उस त्रुटि को निम्न-स्तर में पकड़ना चाहूँगा (जहाँ मुझे SQL कमांड पता है कि त्रुटि हुई थी) तो मैं उस जानकारी को पकड़ सकता हूँ और अतिरिक्त जानकारी के साथ पुन: विचार कर सकता हूँ । कृपया यहां जादू शब्द पर ध्यान दें: रीथ्रो, और निगल नहीं ।
अपवाद से निपटने का पहला नियम: अपवादों को न निगलें । इसके अलावा, ध्यान दें कि मेरे आंतरिक कैच को कुछ भी लॉग इन करने की आवश्यकता नहीं है क्योंकि बाहरी कैच में पूरे स्टैक ट्रेस होंगे और इसे लॉग कर सकते हैं।
कुछ स्थितियों में आपके पास आदेशों का एक क्रम होता है, और यदि उनमें से कोई भी विफल हो जाता है, तो आपको संसाधनों की सफाई / निपटान करना चाहिए (*), क्या यह एक अपरिवर्तनीय स्थिति है (जिसे फेंक दिया जाना चाहिए) या एक पुनर्प्राप्त करने योग्य स्थिति (जिस मामले में आप स्थानीय रूप से या कॉलर कोड में हैंडल करें लेकिन आपको अपवादों की आवश्यकता नहीं है)। जाहिर है कि प्रत्येक विधि के बाद त्रुटि कोड का परीक्षण करने के बजाय, और अंत में ब्लॉक में निपटाने / निपटाने के बजाय उन सभी आदेशों को एक ही प्रयास में रखना बहुत आसान है। कृपया ध्यान दें कि यदि आप बबल अप करने के लिए त्रुटि चाहते हैं (जो कि शायद आप चाहते हैं), तो आपको इसे पकड़ने की भी आवश्यकता नहीं है - आप अंत में सफाई / निपटान के लिए उपयोग करते हैं - यदि आप चाहते हैं तो आपको केवल कैच / रिट्रो का उपयोग करना चाहिए प्रासंगिक जानकारी जोड़ने के लिए (बुलेट 2 देखें)।
एक उदाहरण लेन-देन ब्लॉक के अंदर एसक्यूएल स्टेटमेंट का एक क्रम होगा। फिर से, यह एक "असहनीय" स्थिति भी है, भले ही आप इसे जल्दी पकड़ने का फैसला करें (इसे स्थानीय रूप से ऊपर तक बुदबुदाने के बजाय इलाज करें) यह अभी भी एक घातक स्थिति है जहां से सबसे अच्छा परिणाम सब कुछ खत्म करना है या कम से कम एक बड़ा गर्भपात करना है। प्रक्रिया का हिस्सा।
(*) यह उस तरह है जैसे on error goto
हमने पुराने Visual Basic में उपयोग किया था
कंस्ट्रक्टर में आप केवल अपवाद फेंक सकते हैं।
यह कहते हुए कि, अन्य सभी स्थितियों में, जहाँ आप कुछ जानकारी लौटा रहे हैं, जिस पर कॉलर 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 यह अभी भी खराब डिजाइन है।