अपवाद प्रचार: मुझे अपवादों को कब पकड़ना चाहिए?


44

मेथोडा मेथडब को कॉल करता है जो बदले में मेथडेक कहता है।

MethodB या MethodC में कोई अपवाद हैंडलिंग नहीं है। लेकिन मेथड में अपवाद हैंडलिंग है।

MethodC में एक अपवाद होता है।

अब, वह अपवाद मेथडब्यू तक बुदबुदा रहा है, जो इसे उचित तरीके से संभालता है।

इसमें गलत क्या है?

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

अपवाद हैंडलिंग के आसपास कथन या सर्वसम्मति फेंकने के लिए है जब निष्पादन केवल एक अपवाद के कारण जारी नहीं रह सकता है। मै समझ गया। लेकिन सभी तरह के ब्लॉक को पकड़ने / पकड़ने की कोशिश करने के बजाय श्रृंखला को छोड़कर अपवाद को क्यों न पकड़ें।

मैं इसे समझता हूं जब आपको संसाधनों को मुक्त करने की आवश्यकता होती है। यह पूरी तरह से एक अलग मामला है।


46
आपको क्या लगता है कि सर्वसम्मति कैच के माध्यम से पास की एक श्रृंखला है?
Caleth

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

14
यदि कोई विधि अपवाद को हैंडल नहीं कर सकती है, और केवल इसे रीथ्रोइंग कर रही है, तो मैं कहूंगा कि यह एक कोड गंध है। यदि कोई विधि अपवाद को नहीं संभाल सकती है, और जब अपवाद को फेंक दिया जाता है, तो उसे कुछ और करने की आवश्यकता नहीं होती है, फिर किसी try-catchब्लॉक की आवश्यकता नहीं है ।
ग्रेग बरगार्ड

7
"इसमें गलत क्या है ?" : कुछ नहीं
इवान

5
पास-थ्रू कैचिंग (जो विभिन्न प्रकारों या उस तरह के अपवादों को नहीं लपेटता) अपवादों के पूरे उद्देश्य को हरा देता है। अपवाद फेंकना एक जटिल तंत्र है, और इसे जानबूझकर बनाया गया था। यदि पास-थ्रू कैच मनचाहा उपयोग मामला था, तो आपको बस एक Result<T>प्रकार (एक ऐसा प्रकार) लागू करना होगा जो या तो एक संगणना, या एक त्रुटि के परिणामस्वरूप), और इसे आपके अन्यथा फेंकने वाले कार्यों से वापस लौटा दे। स्टैक अप में किसी त्रुटि का प्रचार करना, प्रत्येक रिटर्न मान को पढ़ना, यदि इसकी त्रुटि है, तो जाँच करना और यदि ऐसा है, तो त्रुटि वापस करना होगा।
सिकंदर

जवाबों:


139

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

एक विधि में कैच और रीथ्रो मेकेनिज्म होने के एकमात्र कारण हैं:

  • आप एक अपवाद को एक दूसरे में बदलना चाहते हैं जो ऊपर दिए गए कॉलर के लिए अधिक सार्थक है।
  • आप अपवाद में अतिरिक्त जानकारी जोड़ना चाहते हैं।
  • आपको उन संसाधनों को साफ करने के लिए कैच क्लॉज की आवश्यकता होती है जो एक के बिना लीक हो जाएंगे।

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


28
@GregBurghardt यदि आपकी भाषा में कुछ है try ... finally ..., तो उसका उपयोग करें, न कि
पकड़ें

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

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

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

14
@Voo आपको लगता है कि "आप एक अपवाद को किसी भिन्न में बदलना चाहते हैं जो कॉल करने वाले के लिए अधिक सार्थक है" कैच / रीथ्रो परिदृश्यों के कारण।
jpmc26

21

इसमें गलत क्या है ?

बिल्कुल कुछ नहीं।

अब, वह अपवाद मेथडब्यू तक बुदबुदा रहा है, जो इसे उचित तरीके से संभालता है।

"इसे उचित तरीके से संभालता है" महत्वपूर्ण हिस्सा है। यह संरचित अपवाद हैंडलिंग का क्रूस है।

यदि आपका कोड अपवाद के साथ "उपयोगी" कुछ कर सकता है, तो इसके लिए जाएं। यदि नहीं, तो अकेले अच्छा होने दें।

। । । क्यों नहीं सभी तरह से नीचे ब्लॉक / पकड़ने की कोशिश करने के बजाय श्रृंखला को अपवाद को पकड़ने के लिए।

ठीक वैसा ही आपको करना चाहिए। यदि आप कोड पढ़ रहे हैं जिसमें हैंडलर / रीथ्रोअर "सभी तरह से नीचे" हैं, तो आप [शायद] कुछ बहुत खराब कोड पढ़ रहे हैं।

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

यहाँ कठिनाई का एक हिस्सा यह है कि, ज्यादातर समय, यह समस्या भी देखने को नहीं मिलेगी, क्योंकि अपवाद हर समय नहीं फेंके जा रहे हैं , लेकिन जब वे होते हैं , तो कार्यक्रम बहुत समय बर्बाद करने वाला है और प्रयास धीरे-धीरे कॉल स्टैक को अनपैक करने के लिए कहीं न कहीं उठने के लिए होता है जो वास्तव में अपवाद के साथ कुछ उपयोगी है।


7
जब आवेदन अपवाद को पकड़ता है तब और भी बुरा होता है, और फिर इसे लॉग इन करता है (जहां उम्मीद है कि यह हमेशा के लिए वहां नहीं बैठेगा) और हमेशा की तरह जारी रखने का प्रयास करता है, तब भी जब यह वास्तव में नहीं हो सकता।
सोलोमन उको

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

@ केविन उस मामले में, catchउच्चतम स्तर पर एक एकल होना चाहिए जो त्रुटि को लॉग करता है और त्रुटि प्रतिक्रिया देता है। catchहर जगह छिड़का नहीं ब्लॉक। यदि आपको ऐसा लगता नहीं है कि हर संभावित जाँच अपवाद (जावा जैसी भाषाओं में) को सूचीबद्ध किया जाए RuntimeException, तो इसे वहाँ लॉग इन करने के बजाय, इसे जारी रखने का प्रयास करें, और अधिक त्रुटियों या कमजोरियों में भी इसे चलाने की कोशिश करें।
सोलोमन उको

8

आपको पुस्तकालयों और अनुप्रयोगों के बीच अंतर करना होगा।

पुस्तकालय बिना किसी अपवाद के स्वतंत्र रूप से फेंक सकते हैं

जब आप एक पुस्तकालय डिजाइन करते हैं, तो कुछ बिंदु पर आपको यह सोचना होगा कि क्या गलत हो सकता है। पैरामीटर गलत श्रेणी में हो सकते हैं या null, बाहरी संसाधन अनुपलब्ध हो सकते हैं, आदि।

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

एप्लिकेशन को हमेशा कुछ बिंदु पर अपवादों को पकड़ना चाहिए

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

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

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


वास्तव में, यदि आपके पास डिस्क लिखने के संचालन जैसे कुछ के लिए एक पुस्तकालय है या कहें, अन्य हार्डवेयर हेरफेर, तो आप सभी प्रकार की अप्रत्याशित घटनाओं को समाप्त कर सकते हैं। क्या होगा अगर एक हार्ड ड्राइव लेखन के दौरान बाहर yanked है? पढ़ते समय सीडी ड्राइव क्या छोटा होता है? यह आपके नियंत्रण से बाहर है और जब आप कुछ कर सकते थे (जैसे, यह दिखावा सफल था), यह अक्सर पुस्तकालय उपयोगकर्ता के लिए एक अपवाद फेंकने और उन्हें तय करने के लिए एक अच्छा अभ्यास है। हो HDDPluggedOutDuringWritingExceptionसकता है कि इससे निपटा जाए और आवेदन के लिए गैर-घातक हो। कार्यक्रम तय कर सकता है कि उसके साथ क्या करना है।
व्लाज

1
@VLAZ क्या घातक है बनाम गैर-घातक कुछ ऐसा है जो आवेदन को तय करना है। पुस्तकालय को बताना चाहिए कि क्या हुआ। एप्लिकेशन को यह तय करना है कि उस पर कैसे प्रतिक्रिया दी जाए।
MechMK1

0

आपके द्वारा वर्णित पैटर्न में क्या गलत है, विधि ए में तीन परिदृश्यों के बीच अंतर करने का कोई तरीका नहीं होगा:

  1. विधि बी एक प्रत्याशित फैशन में विफल रही।

  2. मेथड B विधि B से प्रत्याशित फैशन में विफल रहा, लेकिन जबकि विधि B एक ऑपरेशन कर रहा था जिसे सुरक्षित रूप से छोड़ दिया जा सकता था।

  3. मेथड B विधि B से प्रत्याशित फैशन में विफल रहा, लेकिन मेथड B एक ऐसा ऑपरेशन कर रहा था, जो चीजों को एक निश्चित-अस्थायी असंगत स्थिति में रखता था, जो C की विफलता के कारण B को साफ करने में विफल था।

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


2
परिदृश्य 2 और 3 विधि बी में बग हैं। विधि ए उन लोगों को ठीक करने का प्रयास नहीं करना चाहिए।
सोजेरड

@Sjoerd: विधि B को किस तरीके से C को विफल करने के सभी तरीकों का अनुमान लगाना चाहिए?
सुपरकैट

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

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

@ Sjoerd मेथड B काफी आसान हो जाता है, इसके बारे में यदि अपवाद भाषा द्वारा निषिद्ध है। क्योंकि उस स्थिति में, आप वास्तव में बी के माध्यम से सभी नियंत्रण प्रवाह पथों को देखते हैं, और आपको दूसरे अनुमान लगाने की ज़रूरत नहीं है कि परिचालक को परिदृश्य से बचने के लिए फेंकने वाले फैशन (C ++) में ओवरलोड किया जा सकता है 3. हम कोड के संदर्भ में बहुत अधिक भुगतान कर रहे हैं स्पष्टता और सुरक्षा के लिए "सिर्फ" अपवादों को फेंककर त्रुटियों को वापस करने के बारे में आलसी होना। क्योंकि, अंत में, त्रुटि हैंडलिंग कोड का एक महत्वपूर्ण हिस्सा है।
शाम
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.