कोशिश पकड़ने-ब्लॉक का अच्छा उपयोग?


15

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

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

संपादित करें:  मुझे इसे थोड़ा अलग तरीके से लिखना चाहिए। मैं विभिन्न प्रकारों के रूप में फिर से फेंकने के लिए समझता हूं और इस तरह, मैंने उस खराब शब्द को कहा और यह मेरी अपनी गलती है। मेरा सवाल है ... ऐसा करते समय कोई सबसे अच्छा कोड को कैसे साफ रखता है? यह बस थोड़ी देर के बाद मेरे लिए बेहद अव्यवस्थित महसूस करना शुरू कर देता है।


कौन सी प्रोग्रामिंग भाषा?
अपाला

2
फिलहाल सी #, लेकिन मैं सामान्य रूप से सोचने की कोशिश कर रहा हूं।
trycatch

सी # फेंके गए अपवादों की घोषणा को बल नहीं देता है, जो अपवादों को संभालना आसान बनाता है, जहां यह उचित है, और प्रोग्रामर को वास्तव में उन्हें संभालने के बिना उन्हें पकड़ने के लिए लुभाने से बचें। Anders Hejlsberg, C # के डिज़ाइनर, इस लेख Artima.com/intv/handcuffs.html
Apalaala

जवाबों:


14

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

इसके अलावा, SQLException को मॉडल के सभी तरीके (या बदतर, UI) को फेंकने के बजाय, प्रत्येक परत को ज्ञात अपवादों को पकड़ना चाहिए और उस परत के अनुकूल अपवादों के साथ लपेटना / बदलना / बदलना चाहिए:

Layer      Handles Exception
----------------------------
UI         DataNotFoundException
Model      DatabaseRetrievalException
DAO        SQLException

यह आपको प्रत्येक परत में दिख रहे अपवादों की संख्या को सीमित करने में मदद करनी चाहिए और एक संगठित अपवाद प्रणाली को बनाए रखने में आपकी मदद करेगी।


मैंने कुछ संपादन किए, जो मूल Q को खराब बताते हैं .. मेरा प्रश्न यह है कि सभी कोशिश करते हुए और पकड़ने के दौरान कोड को कैसे साफ रखा जाए और क्या नहीं। यह बहुत गन्दा लगने लगता है जब हर जगह पकड़ने की कोशिश की जाती है ...
trycatch

1
@ क्या यह आपको परेशान नहीं करता है कि आपका UI या मॉडल "SQLException" को पकड़ रहा है? मेरे लिए, यह बहुत प्रासंगिक नहीं है। मुझे लगता है अपने हरेक व्यक्ति के लिए।
निकोल

1
@ ईडी, यह उन भाषाओं में ठीक हो सकता है, जिन्होंने अपवादों की जाँच नहीं की है, लेकिन जाँच किए गए अपवादों वाली भाषाओं में, यह वास्तव में बदसूरत है throws SQLExceptionएक ऐसी विधि है जो SQL को भी शामिल नहीं करती है। और क्या होता है अगर आप तय करते हैं कि कुछ संचालन एक फ़ाइल स्टोर पर जाना चाहिए? अब आपको घोषणा करनी होगी throws SQLException, IOException, आदि यह हाथ से निकल जाएगा।
माइक डेनियल

1
@ अंतिम उपयोगकर्ता के लिए SQLException का ज्यादा मतलब नहीं है, खासकर यदि आपका सिस्टम रिलेशनल डेटाबेस के अलावा कई प्रकार के दृढ़ता का समर्थन कर सकता है। एक गिनी प्रोग्रामर के रूप में मुझे बहुत कम डेटा अपवादों के एक पूरे सेट की तुलना में DataNotFoundException से निपटना होगा। अक्सर निम्न स्तर की लाइब्रेरी के लिए एक अपवाद ऊपर के सामान्य जीवन का हिस्सा है, इस मामले में वे संभालना बहुत आसान होते हैं जब उनके स्तर के अमूर्त आवेदन के स्तर से मेल खाते हैं।
न्यूटोपियन

1
@ न्यूटोपियन - मैंने कभी भी अंतिम उपयोगकर्ता के लिए कच्चा अपवाद पेश नहीं किया। उपयोगकर्ताओं को समाप्त करने के लिए, एक सरल 'प्रोग्राम ने काम करना बंद कर दिया' संदेश एक्सेप्शन को लॉग-इन करने के लिए पर्याप्त है और समर्थन लेने के लिए कहीं उपयोगी है। डीबग मोड में यह अपवाद प्रदर्शित करने के लिए उपयोगी है। आपको हर संभव अपवाद की परवाह नहीं करनी चाहिए, जब तक कि आपके पास ऐसे अपवादों के लिए एक विशिष्ट हैंडलर न हो, एक एपीआई फेंक सकता है; बस अपने Un-Handled Exception कैचर को इससे निपटने दें।
एड जेम्स

9

अपवाद क्लीनर कोड लिखने की अनुमति देते हैं क्योंकि इसका थोक सामान्य मामले का ख्याल रखता है, और असाधारण मामलों को बाद में भी अलग संदर्भ में संभाला जा सकता है।

अपवादों को संभालने (पकड़ने) का नियम यह है कि इसे इस संदर्भ में किया जाना चाहिए कि वास्तव में इसके बारे में कुछ किया जा सकता है। लेकिन इसकी एक छूट है:

अपवादों को मॉड्यूल सीमाओं (विशेष रूप से परत की सीमाओं) पर पकड़ा जाना चाहिए और यहां तक ​​कि अगर केवल उन्हें घेरने के लिए उच्च स्तर के अपवाद को फेंकना है जिसका कॉलर को अर्थ है। प्रत्येक मॉड्यूल और परत को अपवादों के संबंध में भी अपने कार्यान्वयन के विवरण को छिपाना चाहिए (एक हीप मॉड्यूल HeapFull फेंक सकता है लेकिन कभी भी ArrayIndexOutOfBounds)।

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


मैं सहमत हूं, और अपने प्रश्न को यह प्रतिबिंबित करने के लिए संपादित किया कि मैंने इसे बुरी तरह से कहां कहा था। मेरा मतलब इसके लिए और अधिक सवाल होना था कि किस तरह से कोशिश करना और पकड़ में आने वाली चीजों को पकड़ना है।
२२:५१ पर

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

1
इस सामान को कोड के उदाहरणों के साथ समझना आसान होगा ..
क्लिक करें

यह शुरू से ही स्टैकओवरफ्लो के लिए बेहतर प्रश्न था।
अपाला

5

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

अन्यथा, इसका अक्सर सबसे अच्छा होता है अपवादों को सतह तक बुलबुले बनाने के लिए ताकि उन्हें उजागर किया जा सके और निपटा जा सके। कुछ लोग इसे फेल-फास्ट कहते हैं।

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

जब आप किसी वितरित सिस्टम पर अपवाद को फेंकने की आवश्यकता होती है, तो अपवाद अपवाद उपयोगी होते हैं और क्लाइंट के पास सर्वर-साइड फॉल्ट की परिभाषा नहीं होती है।


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

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

2
फिर से यह सब इस बात पर निर्भर करता है कि आप क्या निर्माण कर रहे हैं, लेकिन मैं आमतौर पर केवल उन्हें बुलबुले बनाने से असहमत हूं क्योंकि यह अमूर्त रिसाव बनाता है। जब मैं एक एपीआई का उपयोग करता हूं तो मैं यह देखूंगा कि यह एपीआई के मॉडल के साथ अपवादों को उजागर करता है। मुझे आश्चर्य भी होता है कि मैं नफरत करता हूं जब एक एपीआई सिर्फ इसे लागू करने से संबंधित अपवाद को अघोषित रूप से देखता है। अगर मुझे पता नहीं है कि मेरे पास क्या आ रहा है तो मैं संभवतः कैसे प्रतिक्रिया दे सकता हूं! मुझे लगता है कि मेरे ऐप को अघोषित रूप से दुर्घटनाग्रस्त होने से बचाने के लिए मैं अक्सर बहुत व्यापक कैच नेट का उपयोग करता हूं।
न्यूटोपियन

@ न्यूटोपियन: "रैपिंग" अपवाद और "रीराइटिंग" सार के रिसाव को कम करते हैं। वे अभी भी उचित रूप से बबल करते हैं। "अगर मुझे कोई पता नहीं है कि मेरे पास क्या आ रहा है तो मैं संभवतः कैसे प्रतिक्रिया कर सकता हूं! मैं खुद को बहुत अधिक व्यापक कैच नेट का उपयोग करता हूं" वह चीज है जो हम आपको सुझाव दे रहे हैं कि आप करना बंद कर दें। आपको सब कुछ पकड़ने की जरूरत नहीं है। 80% समय, सही बात कुछ भी नहीं पकड़ना है। समय का 20% एक सार्थक प्रतिक्रिया है।
एस.लॉट

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

4

कल्पना कीजिए कि आप स्टैक क्लास लिख रहे हैं। आप कक्षा में किसी भी अपवाद हैंडलिंग कोड को नहीं डालते हैं, जिसके परिणामस्वरूप यह निम्नलिखित अपवाद उत्पन्न कर सकता है।

  1. ArrayIndexError - जब उपयोगकर्ता खाली स्टैक से पॉप करने का प्रयास करता है तो उठाया जाता है
  2. NullPtrException - कार्यान्वयन में बग के कारण उठाया गया, जिससे अशक्त संदर्भ को संदर्भित करने का प्रयास हो सकता है

रैपिंग अपवादों के लिए एक सरलीकृत दृष्टिकोण इन दोनों अपवादों को स्टैकरर अपवाद अपवाद वर्ग में लपेटने का निर्णय ले सकता है। हालांकि, यह वास्तव में अपवादों को लपेटने की बात को याद करता है। यदि कोई वस्तु एक निम्न-स्तरीय अपवाद फेंकता है जिसका अर्थ यह होना चाहिए कि वस्तु टूट गई है। हालांकि, एक मामला है जहां यह स्वीकार्य है: जब वस्तु वास्तव में टूटी हुई है।

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

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

इसे SQLException के अपने उदाहरण में वापस लाने के लिए: आपको SQLException क्यों मिल रही हैं? एक कारण यह है कि आप अमान्य क्वेरी से गुजर रहे हैं। हालाँकि, यदि आपकी डेटा एक्सेस लेयर खराब क्वेरीज़ उत्पन्न कर रही है, तो उसका टूटना। यह DataAccessFailure अपवाद में अपनी टूटने की पुनरावृत्ति का प्रयास नहीं करना चाहिए।

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

मुझे नहीं पता कि आपका कोड कैसा दिखता है। लेकिन ऐसा लगता है कि आप आँख बंद करके उच्च स्तर के अपवादों में सभी अपवादों का अनुवाद कर सकते हैं। आपको केवल अपेक्षाकृत कम मामलों में ऐसा करना चाहिए। अधिकांश निचले स्तर के अपवाद आपके कोड में बग दर्शाते हैं। उन्हें पकड़ना और फिर से तैयार करना प्रति-उत्पादक है।

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