त्रुटि से निपटने का आधुनिक तरीका ...


118

मैं अब कुछ समय के लिए इस समस्या को हल कर रहा हूं और खुद को लगातार कैविट और विरोधाभास ढूंढ रहा हूं, इसलिए मुझे उम्मीद है कि कोई व्यक्ति निम्नलिखित के लिए एक निष्कर्ष निकाल सकता है:

त्रुटि कोड पर अनुकूल अपवाद

जहाँ तक मुझे जानकारी है, उद्योग में चार साल से काम करने से लेकर, किताबें और ब्लॉग पढ़ने आदि, त्रुटियों को संभालने के लिए मौजूदा सबसे अच्छा अभ्यास है, अपवाद कोड फेंकने के बजाय, त्रुटि कोड वापस करना (जरूरी नहीं कि त्रुटि कोड हो, लेकिन ए टाइप करें)

लेकिन - मुझे यह विरोधाभास लगता है ...

इंटरफेस के लिए कोडिंग, कार्यान्वयन नहीं

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

जब तक - इंटरफ़ेस है ...

अपवाद विनिर्देशों

कुछ भाषाएं डेवलपर्स को throwsयह बताने की अनुमति देती हैं कि कुछ विधियाँ कुछ अपवाद (उदाहरण के लिए जावा, कीवर्ड का उपयोग करती हैं ।) कॉलिंग कोड के दृष्टिकोण से यह ठीक लगती हैं - हम स्पष्ट रूप से जानते हैं कि हमें किन अपवादों को पकड़ने की आवश्यकता हो सकती है।

लेकिन - यह एक सुझाव है लगता है ...

लीक से हटकर

एक इंटरफ़ेस को क्यों निर्दिष्ट करना चाहिए जो अपवादों को फेंका जा सकता है? क्या होगा यदि कार्यान्वयन को एक अपवाद को फेंकने की आवश्यकता नहीं है, या अन्य अपवादों को फेंकने की आवश्यकता है? इंटरफ़ेस स्तर पर, कोई तरीका नहीं है, यह जानने के लिए कि कौन सा अपवाद लागू करना चाहता है।

इसलिए...

समाप्त करने के लिए

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


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

@deceze एक इंटरफ़ेस संभवतः कैसे बता सकता है कि कार्यान्वयन क्या फेंक सकता है? यह प्रकार प्रणाली में सभी अपवादों को फेंक सकता है! और कई भाषाओं के अपवाद विनिर्देशों का समर्थन नहीं करते वे सुझाव देते हैं कि वे बहुत
प्यारे हैं

1
मैं सहमत हूँ कि यह सभी अलग-अलग अपवादों को प्रबंधित करने के लिए मुश्किल हो सकता है एक विधि फेंक सकती है, अगर यह स्वयं अन्य विधियों का उपयोग करता है और आंतरिक रूप से उनके अपवादों को नहीं पकड़ता है। कहा कि, यह एक विरोधाभास नहीं है।
deceze

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

जवाबों:


31

सबसे पहले, मैं इस कथन से असहमत होगा:

त्रुटि कोड पर अनुकूल अपवाद

यह हमेशा ऐसा नहीं होता है: उदाहरण के लिए, ऑब्जेक्टिव-सी (फाउंडेशन ढांचे के साथ) पर एक नज़र डालें। वहाँ NSError त्रुटियों को संभालने का पसंदीदा तरीका है, एक जावा डेवलपर के अस्तित्व के बावजूद, असली अपवाद क्या कहेंगे: @try, @catch, @throw, NSException class, आदि।

हालाँकि यह सच है कि कई इंटरफेस अपवादों के साथ अपने सार को लीक करते हैं। यह मेरा विश्वास है कि यह "प्रचार" के दोष का नहीं है- त्रुटि को फैलाने / संभालने की शैली। सामान्य तौर पर मेरा मानना ​​है कि त्रुटि से निपटने के बारे में सबसे अच्छी सलाह यह है:

न्यूनतम संभव स्तर, अवधि में त्रुटि / अपवाद से निपटें

मुझे लगता है कि अगर कोई अंगूठे के उस नियम से चिपक जाता है, तो अमूर्तता से "रिसाव" की मात्रा बहुत सीमित और निहित हो सकती है।

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

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

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

इसके अलावा, मुझे लगता है कि जावा के रचनाकारों में अपवादों को एक विधि घोषणा / परिभाषा में शामिल करने के लिए बहुत मजबूत सुरक्षा कारण थे।

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


12
+1 के लिए "त्रुटि कोड पर अनुकूल अपवाद।" मुझे सिखाया गया है कि अपवाद अच्छी तरह से और अच्छे हैं, इसलिए जब तक वे वास्तव में हैं, अपवाद और नियम नहीं। एक विधि को कॉल करना जो यह निर्धारित करने के लिए एक अपवाद फेंकता है कि क्या कोई शर्त सच है या नहीं, अत्यंत बुरा अभ्यास है।
नील

4
@ जोशुआड्रे: वह निश्चित रूप से गलत है। अपवाद और gotoबहुत अलग हैं। उदाहरण के लिए, अपवाद हमेशा एक ही दिशा में जाते हैं- कॉल स्टैक नीचे। और दूसरी बात, आश्चर्य अपवादों से खुद को बचाना DRY- के समान ही अभ्यास है, उदाहरण के लिए, C ++ में, यदि आप सफाई सुनिश्चित करने के लिए RAII का उपयोग करते हैं, तो यह सभी मामलों में क्लीनअप सुनिश्चित करता है , न केवल अपवाद बल्कि सभी सामान्य नियंत्रण प्रवाह। यह असीम रूप से अधिक विश्वसनीय है। try/finallyकुछ इसी तरह पूरा करता है। जब आप ठीक से सफाई की गारंटी देते हैं, तो आपको विशेष मामले के अपवादों पर विचार करने की आवश्यकता नहीं है।
डेडएमजेड

4
@JoshuaDrake क्षमा करें, लेकिन जोएल वहाँ से दूर है। अपवाद गोटो के समान नहीं हैं, आप हमेशा कॉल स्टैक तक कम से कम एक स्तर तक जाते हैं। और अगर ऊपर का स्तर त्रुटि कोड से तुरंत निपट नहीं सकता है तो आप क्या करते हैं? एक और त्रुटि कोड लौटाएं? त्रुटि के साथ समस्या का एक हिस्सा यह है कि उन्हें अनदेखा किया जा सकता है, जिससे अपवाद को फेंकने की तुलना में बदतर समस्याएं हो सकती हैं।
एंडी

25
-1 क्योंकि मैं पूरी तरह से "न्यूनतम स्तर पर त्रुटि / अपवाद के साथ सौदा" से असहमत हूं - यह गलत, अवधि है। उपयुक्त स्तर पर त्रुटियों / अपवादों से निपटें । बहुत बार यह एक उच्च स्तर है, और उस स्थिति में, त्रुटि कोड एक बहुत बड़ा दर्द है। त्रुटि कोड पर अपवाद का कारण यह है कि वे आपको स्वतंत्र रूप से चुनने की अनुमति देते हैं कि बीच के स्तरों को प्रभावित किए बिना उनके साथ किस स्तर पर व्यवहार करें।
माइकल बोर्गवर्ड

2
@Giorgio: देखने artima.com/intv/handcuffs.html - विशेष रूप से पेज 2 और 3
माइकल Borgwardt

27

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

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

func x = do
    a <- operationThatMightFail 10
    b <- operationThatMightFail 20
    c <- operationThatMightFail 30
    return (a + b + c)

OperationThatMightfail एक ऐसा फंक्शन है जो एक मान को लिपटे हुए देता है। यह एक अशक्त सूचक की तरह काम करता है, लेकिन यह नोटेशन गारंटी देता है कि यदि कोई भी, बी या सी असफल नहीं होता है, तो पूरी चीज शून्य का मूल्यांकन करती है। (और संकलक आपको आकस्मिक NullPointerException बनाने से बचाता है)

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

कॉमन LISP ऐसा करता है, और इसे सिंटैटिक सपोर्ट (निहित तर्क) देकर और इस प्रोटोकॉल का पालन करते हुए इसे संभव बनाता है।


1
यह वास्तव में साफ है। विकल्प के बारे में जवाब देने के लिए धन्यवाद :)
रिचके

1
BTW, अपवाद आधुनिक अनिवार्य भाषाओं के सबसे कार्यात्मक भागों में से एक है। अपवाद एक मठ बनाते हैं। अपवाद संरक्षक मिलान का उपयोग करते हैं। अपवाद वास्तव में जो कुछ भी Maybeहै उसे सीखने के बिना आवेदन शैली की नकल करने में मदद करते हैं ।
9000

मैं हाल ही में SML के बारे में एक पुस्तक पढ़ रहा था। इसमें विकल्प प्रकार, अपवाद (और निरंतरता) का उल्लेख किया गया है। सलाह विकल्प के प्रकारों का उपयोग करने के लिए थी जब अपरिभाषित मामले के बजाय अक्सर होने की उम्मीद होती है, और अपवाद का उपयोग करने के लिए जब अपरिभाषित मामला बहुत कम होता है।
जियोर्जियो

8

हाँ, अपवाद लीक सार का कारण बन सकते हैं। लेकिन क्या इस संबंध में त्रुटि कोड भी बदतर नहीं हैं?

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

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

वास्तव में, त्रुटि कोड के साथ, बहुत अधिक एक ही बात समाप्त हो रही है, बस एक और अधिक निहित फैशन में, और जानकारी खो जाने की अधिक संभावना के साथ और ऐप असंगत स्थिति में समाप्त हो रहा है।


1
मुझे समझ में नहीं आता कि एक त्रुटि कोड एक टपका हुआ अमूर्त क्यों पैदा कर सकता है। यदि सामान्य रिटर्न मान के बजाय एक त्रुटि कोड दिया जाता है, और यह व्यवहार फ़ंक्शन / विधि के विनिर्देश में वर्णित है, तो IMO कोई रिसाव नहीं है। या मैं कुछ देख रहा हूँ?
जियोर्जियो

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

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

1
@ जियोर्जियो: हां, कार्यान्वयन-विशिष्ट त्रुटियों की रिपोर्टिंग कार्यान्वयन-अज्ञेय एपीआई के साथ मुश्किल है। फिर भी, आप इसे अपवादों के साथ कर सकते हैं, क्योंकि (त्रुटि कोड के विपरीत) उनके पास कई क्षेत्र हो सकते हैं। तो आप सामान्य त्रुटि जानकारी (ResourceMissingException) प्रदान करने के लिए अपवाद के प्रकार का उपयोग कर सकते हैं, और एक फ़ील्ड के रूप में कार्यान्वयन-विशिष्ट गलत कोड / संदेश शामिल कर सकते हैं। दोनों ओर से लाभदायक :-)।
sleske

और BTW, कि सिर्फ java.lang.SQLException क्या करता है। इसमें getSQLState(सामान्य) और getErrorCode(विक्रेता-विशिष्ट) है। अब अगर केवल यह ... उचित उपवर्गों था
sleske

5

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

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

अपवाद उपयोग का एक और पतित मामला मैंने देखा है, जिनकी पहली प्रतिक्रिया "एक अपवाद फेंकना" है। यह लगभग हमेशा कैच लिखने के बिना किया जाता है (अंगूठे का नियम: पहले कैच लिखें, फिर थ्रो स्टेटमेंट)। बड़े अनुप्रयोगों में यह समस्याग्रस्त हो जाता है जब एक अनकहा अपवाद nether- क्षेत्रों से अलग हो जाता है और कार्यक्रम को उड़ा देता है।

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


4

लीक से हटकर

एक इंटरफ़ेस को क्यों निर्दिष्ट करना चाहिए जो अपवादों को फेंका जा सकता है? क्या होगा यदि कार्यान्वयन को एक अपवाद को फेंकने की आवश्यकता नहीं है, या अन्य अपवादों को फेंकने की आवश्यकता है? इंटरफ़ेस स्तर पर, कोई तरीका नहीं है, यह जानने के लिए कि कौन सा अपवाद लागू करना चाहता है।

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

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


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

@ मिस्सिंगो: ऐसा इसलिए है, क्योंकि हमेशा की तरह, जावा में उनका भयानक कार्यान्वयन है, इसलिए नहीं कि जाँच किए गए अपवाद स्वाभाविक रूप से खराब हैं।
डेडएमजेड

1
@ मिस्सिंगो: चेक किए गए अपवादों के कारण किस प्रकार की समस्याएं हो सकती हैं?
जियोर्जियो

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

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

2

वैसे एक्सेप्शन हैंडलिंग का अपना इंटरफ़ेस कार्यान्वयन हो सकता है। अपवाद के प्रकार के आधार पर, वांछित चरणों का प्रदर्शन करें।

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

त्रुटि कोड का कार्यान्वयन अपवाद को संभालने का एक रूढ़िवादी तरीका है। यह स्ट्रिंग बनाम स्ट्रिंग बिल्डर के उपयोग की तरह है।


4
दूसरे शब्दों में: कार्यान्वयन एपि में परिभाषित अपवादों के उपवर्गों को फेंक देते हैं।
andrew cooke

2

IM-very-HO अपवादों को केस के आधार पर एक मामले में आंका जाना है, क्योंकि नियंत्रण प्रवाह को तोड़ने से वे आपके कोड की वास्तविक और कथित जटिलता को बढ़ाएंगे, कई मामलों में अनावश्यक रूप से। अपने कार्यों के अंदर अपवादों को फेंकने से संबंधित चर्चा को अलग रखना - जो वास्तव में आपके नियंत्रण प्रवाह में सुधार कर सकता है, अगर किसी को कॉल सीमाओं के माध्यम से अपवादों को देखना है, तो निम्नलिखित पर विचार करें:

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

उपरोक्त अवलोकन किसी भी शिथिल युग्मित इंटरफ़ेस तक बढ़ाया जा सकता है (जैसा आपने बताया); मुझे लगता है कि यह वास्तव में एक मानक है कि 3-6 स्टैक फ्रेम को रेंगने के बाद, एक अनकहा अपवाद कोड के एक भाग में समाप्त होने की संभावना है: या तो:

  • किसी भी सार्थक तरीके से अपवाद से निपटने के लिए बहुत सार है, भले ही अपवाद खुद को ऊपर उठाया हो;
  • एक सामान्य कार्य कर रहा है (इस बात की कम परवाह नहीं कर सकता कि आप असफल क्यों हुए, जैसे संदेश पंप, या अवलोकन योग्य);
  • विशिष्ट है, लेकिन एक अलग जिम्मेदारी के साथ, और यह वास्तव में चिंता नहीं करनी चाहिए;

उपर्युक्त को ध्यान में रखते हुए, throwsशब्दार्थ के साथ इंटरफेस को बनाना केवल एक मामूली कार्यात्मक लाभ है, क्योंकि बहुत सारे कॉलर इंटरफ़ेस अनुबंधों के माध्यम से ही देखभाल करेंगे यदि आप असफल हुए, तो क्यों नहीं।

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

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


1

त्रुटि कोड पर अनुकूल अपवाद

  • दोनों को साथ होना चाहिए।

  • जब आप कुछ व्यवहार का अनुमान लगाते हैं, तो त्रुटि कोड लौटाएं।

  • अपवाद छोड़ें जब आपने कुछ व्यवहार की आशंका नहीं की थी।

  • त्रुटि कोड आम तौर पर एक संदेश के साथ जुड़े होते हैं, जब अपवाद प्रकार रहता है, लेकिन एक संदेश भिन्न हो सकता है

  • अपवाद में स्टैक ट्रेस होता है, जब त्रुटि कोड नहीं होता है। मैं टूटी हुई प्रणाली को डीबग करने के लिए त्रुटि कोड का उपयोग नहीं करता हूं।

इंटरफेसिंग के लिए कोडिंग कार्यान्वयन नहीं

यह JAVA के लिए विशिष्ट हो सकता है, लेकिन जब मैं अपने इंटरफेस की घोषणा करता हूं तो मैं यह निर्दिष्ट नहीं करता कि उस इंटरफ़ेस के कार्यान्वयन से क्या अपवाद हो सकते हैं, यह सिर्फ समझ में नहीं आता है।

जब हम एक अपवाद को पकड़ते हैं तो निश्चित रूप से हम कार्यान्वयन के बारे में धारणा बना रहे हैं?

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

क्या होगा यदि कार्यान्वयन को एक अपवाद को फेंकने की आवश्यकता नहीं है, या अन्य अपवादों को फेंकने की आवश्यकता है?

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

क्या यह कुछ भी बदल जाएगा यदि अपवाद के बजाय आपके कार्यान्वयन ने परिणाम वस्तु वापस कर दी? इस ऑब्जेक्ट में किसी भी त्रुटि / विफलताओं के साथ आपकी कार्रवाई के परिणाम शामिल होंगे यदि कोई हो। फिर आप उस वस्तु से पूछताछ कर सकते हैं।


1

लीक से हटकर

एक इंटरफ़ेस को क्यों निर्दिष्ट करना चाहिए जो अपवादों को फेंका जा सकता है? क्या होगा यदि कार्यान्वयन को एक अपवाद को फेंकने की आवश्यकता नहीं है, या अन्य अपवादों को फेंकने की आवश्यकता है? इंटरफ़ेस स्तर पर, कोई तरीका नहीं है, यह जानने के लिए कि कौन सा अपवाद लागू करना चाहता है।

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

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


1

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

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

सारांश:

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

1
मैं असहमत हूं। हां, अनकैप्ड अपवाद किसी एप्लिकेशन को क्रैश कर सकते हैं, लेकिन अनियंत्रित त्रुटि कोड भी हो सकते हैं - इसलिए यह धोना है। यदि आप अपवादों का ठीक से उपयोग करते हैं, तो केवल अनकैप्ड ही घातक होंगे (जैसे आउटऑफमेरी), और इन के लिए, तुरंत दुर्घटनाग्रस्त होना सबसे अच्छा है जो आप कर सकते हैं।
sleske

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

सबसे पहले: आप सभी अपवादों को जाँच कर सकते हैं - बस कर "पोकीमॉन अपवाद हैंडलिंग" (उन सब को पकड़ने होगा - यानी catch Exceptionया यहाँ तक कि Throwable, या समकक्ष)।
sleske

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

-1

राइट-बायस्ड या तो।

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

नकारात्मक पहलू? उचित त्रुटि से निपटने वाला कोड घृणित (सभी तंत्रों का सच) दिखता है।


ऐसा लगता नहीं है कि पहले से बनाए गए 10 से अधिक उत्तरों में कुछ भी स्पष्ट नहीं किया गया है। सामान के साथ दो साल पुराना सवाल क्यों टकरा रहा है
gnat

सिवाय यहाँ किसी ने भी सही पक्षपाती का उल्लेख नहीं किया। hugomg के पास हैक्सेल के बारे में बात करना बंद हो गया, हालांकि हो सकता है कि वह एक त्रुटि त्रुटि हैंडलर हो, क्योंकि यह इस बात का कोई विवरण नहीं देता है कि त्रुटि क्यों हुई, और न ही कोई प्रत्यक्ष विधि जिसके साथ पुनर्प्राप्त करना है, और कॉल-बैक नियंत्रण प्रवाह डिजाइन में सबसे बड़े पापों में से एक है। और यह सवाल google पर आया।
कीनन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.