क्यों उपयोग करने की कोशिश ... अंत में एक पकड़ खंड के बिना?


79

कार्यक्रम का शास्त्रीय तरीका है try ... catchtryबिना उपयोग करना कब उचित है catch?

पायथन में निम्नलिखित कानूनी प्रतीत होता है और समझ में आ सकता है:

try:
  #do work
finally:
  #do something unconditional

हालाँकि, कोड में catchकुछ भी नहीं था । इसी प्रकार कोई जावा में सोच सकता है कि यह इस प्रकार है:

try {
    //for example try to get a database connection
}
finally {
  //closeConnection(connection)
}

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

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


4
जावा में, कोशिश ब्लॉक के अंत में रिटर्न स्टेटमेंट क्यों नहीं डाला गया?
केविन क्लाइन

2
मुझे दुःख है कि कोशिश करते हैं..बिना कोशिश और कोशिश करते हैं..क्योंकि दोनों ही कोशिश कीवर्ड का उपयोग करते हैं, इसके अलावा दोनों की कोशिश के साथ शुरू करने से वे 2 बिल्कुल अलग निर्माण हैं।
पीटर बी

3
try/catch"प्रोग्राम करने का शास्त्रीय तरीका नहीं है।" यह शास्त्रीय C ++ प्रोग्राम का तरीका है, क्योंकि C ++ में एक उचित प्रयास / अंत में निर्माण का अभाव है, जिसका अर्थ है कि आपको RAII से संबंधित बदसूरत हैक का उपयोग करके गारंटीकृत प्रतिवर्ती राज्य परिवर्तनों को लागू करना होगा। लेकिन सभ्य ओओ भाषाओं में वह समस्या नहीं है, क्योंकि वे कोशिश / अंत में प्रदान करते हैं। यह कोशिश / पकड़ने की तुलना में बहुत अलग उद्देश्य के लिए उपयोग किया जाता है।
मेसन व्हीलर

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

4
@MasonWheeler "बदसूरत हैक्स" कृपया, क्या एक वस्तु को संभालने के बारे में बुरा है यह खुद की सफाई है?
बाल्ड्रिक

जवाबों:


146

यह इस बात पर निर्भर करता है कि आप इस बिंदु पर उठाए जा सकने वाले अपवादों से निपट सकते हैं या नहीं।

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

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

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


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

13
@will - इसलिए मैंने "संभव के रूप में" वाक्यांश का उपयोग किया।
ChrisF

8
अच्छा जवाब है, लेकिन मैं एक उदाहरण जोड़ूंगा: एक स्ट्रीम खोलना और उस स्ट्रीम को लोड करने के लिए एक आंतरिक विधि से गुजरना जब आप की आवश्यकता होगी का एक उत्कृष्ट उदाहरण है try { } finally { }, स्ट्रीम का लाभ उठाने के लिए अंत में यह सुनिश्चित करने के लिए कि सफलता की परवाह किए बिना अंततः बंद हो गया है / विफलता।
नील

क्योंकि कभी-कभी शीर्ष पर सभी तरह से पास होता है जैसे कोई कर सकता है
न्यूटोपियन

"बस एक कोशिश / अंत में ब्लॉक पूरी तरह से उचित है" बिल्कुल इस जवाब के लिए देख रहा था। साभार @ChrisF
neal aise

36

finallyब्लॉक, कोड है कि हमेशा चलाना चाहिए के लिए प्रयोग किया जाता है कि क्या एक त्रुटि हालत (अपवाद) हुआ है या नहीं।

finallyब्लॉक में कोड tryब्लॉक पूरा होने के बाद चलाया जाता है और, यदि पकड़ा गया अपवाद तब होता है, जब संबंधित catchब्लॉक पूरा हो जाता है। यह हमेशा चलाया जाता है, भले ही कोई अनकहा अपवाद tryया catchब्लॉक में हुआ हो ।

finallyब्लॉक आम तौर पर बंद करने फ़ाइलें, नेटवर्क कनेक्शन, आदि है कि में खोला गया के लिए प्रयोग किया जाता है tryब्लॉक। इसका कारण यह है कि फ़ाइल या नेटवर्क कनेक्शन बंद होना चाहिए, चाहे उस फ़ाइल या नेटवर्क कनेक्शन का उपयोग करने वाला ऑपरेशन सफल हुआ हो या नहीं।

finallyब्लॉक में देखभाल यह सुनिश्चित करने के लिए की जानी चाहिए कि यह खुद एक अपवाद न फेंक दे। उदाहरण के लिए null, आदि के लिए सभी चर जाँचना सुनिश्चित करें ।


8
+1: यह "साफ होना चाहिए" के लिए मुहावरेदार है। अधिकांश उपयोगों को try-finallyएक withबयान से बदला जा सकता है ।
एस.लॉट

12
विभिन्न भाषाओं में try/finallyनिर्माण के लिए अत्यंत उपयोगी भाषा-विशिष्ट संवर्द्धन हैं । C # है using, Python has with, etc.
yfeldblum

5
@yfeldblum - के बीच एक सूक्ष्म अंतर होता है usingऔर try-finally, यदि ऑब्जेक्ट के कंस्ट्रक्टर में अपवाद होता है, तो Disposeविधि को usingब्लॉक द्वारा नहीं बुलाया जाएगा IDisposabletry-finallyआपको कोड को निष्पादित करने की अनुमति देता है, भले ही ऑब्जेक्ट का निर्माता अपवाद फेंकता हो।
स्कॉट व्हिटलॉक

5
@ScottWhitlock: यह एक अच्छी बात है? आप क्या करने की कोशिश कर रहे हैं, एक असंबंधित वस्तु पर एक विधि कहते हैं? यह एक अरब प्रकार का बुरा है।
डेडएमजी

1
@DeadMG यह भी देखें: stackoverflow.com/q/14830534/18192
ब्रायन

17

एक उदाहरण जहां कोशिश करते हैं ... अंत में बिना कैच क्लॉज के जावा में उचित (और इससे भी अधिक, मुहावरेदार ) उचित उपयोगिताओं लॉक पैकेज में लॉक का उपयोग होता है ।

  • यहां बताया गया है कि एपीआई प्रलेखन में यह कैसे समझाया और उचित है (बोली में बोल्ड फ़ॉन्ट मेरा है):

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

     Lock l = ...;
     l.lock();
     try {
         // access the resource protected by this lock
     } finally {
         l.unlock();
     }

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


क्या मैं l.lock()कोशिश कर सकता हूँ ? try{ l.lock(); }finally{l.unlock();}
RMachnik

1
तकनीकी रूप से, आप कर सकते हैं। मैंने इसे वहाँ नहीं रखा क्योंकि शब्दार्थ से, यह कम समझ में आता है। tryइस स्निपेट में संसाधन पहुंच को लपेटने का इरादा है, क्यों इसे कुछ के साथ असंबंधित प्रदूषित किया जा रहा है
gnat

4
आप कर सकते हैं, लेकिन यदि l.lock()विफल रहता है, तो finallyब्लॉक अभी भी चलेगा यदि ब्लॉक के l.lock()अंदर है try। यदि आप इसे पसंद करते हैं जैसे कि gnat का सुझाव है, तो finallyब्लॉक केवल तभी चलेगा जब हमें पता चलेगा कि लॉक का अधिग्रहण किया गया था।
वॉटम्यूट

12

एक बुनियादी स्तर पर catchऔर finallyदो संबंधित लेकिन विभिन्न समस्याओं को हल:

  • catch एक समस्या को संभालने के लिए उपयोग किया जाता है जिसे आपके द्वारा कॉल किए गए कोड द्वारा रिपोर्ट किया गया था
  • finally डेटा / संसाधनों को साफ करने के लिए उपयोग किया जाता है जो कि वर्तमान कोड बनाया / संशोधित किया गया है, भले ही कोई समस्या हुई हो या नहीं

इसलिए दोनों किसी भी तरह से समस्याओं (अपवादों) से संबंधित हैं, लेकिन यह बहुत ज्यादा है जो वे सभी में हैं।

एक महत्वपूर्ण अंतर यह है कि finallyब्लॉक उसी विधि में होना चाहिए जहां संसाधन बनाए गए (संसाधन लीक से बचने के लिए) और कॉल स्टैक में एक अलग स्तर पर नहीं डाला जा सकता है।

catchहालांकि अलग बात है: इसके लिए सही जगह पर निर्भर करता है जहाँ आप वास्तव में संभाल कर सकते हैं अपवाद। ऐसे स्थान पर एक अपवाद को पकड़ने में कोई फायदा नहीं है जहां आप इसके बारे में कुछ नहीं कर सकते हैं, इसलिए कभी-कभी बस इसे गिरने देना बेहतर होता है।


2
नाइटपिक: "... अंतत: ब्लॉक उसी विधि में होना चाहिए जहां संसाधन बनाए गए ..." । यह निश्चित रूप से एक अच्छा विचार है कि इसे इस तरह से करें, क्योंकि यह देखना आसान है कि कोई संसाधन रिसाव नहीं है। हालांकि, यह एक आवश्यक पूर्व शर्त नहीं है; यानी आप नहीं है करने के लिए है इसे उस तरह से करते हैं। आप finallyप्रयास स्टेटमेंट को संलग्न करते हुए (सांख्यिकीय या गतिशील रूप से) संसाधन जारी कर सकते हैं ... और अभी भी 100% लीक-प्रूफ हो सकते हैं।
स्टीफन सी

6

@yfeldblum का सही उत्तर है: अंत में बिना कैच स्टेटमेंट के, आमतौर पर एक उपयुक्त भाषा निर्माण के साथ प्रतिस्थापित किया जाना चाहिए।

C ++ में, यह RAII और कंस्ट्रक्टर / डिस्ट्रक्टर्स का उपयोग कर रहा है; अजगर में यह एक withबयान है; और सी # में, यह एक usingबयान है।

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


2
और जावा में यह एआरएम ब्लॉक है
MarkJ

2
मान लें कि आपके पास एक बुरी तरह से डिज़ाइन की गई वस्तु है (उदाहरण के लिए, वह जो उचित रूप से C # में आईडीसिसोप्लग लागू नहीं करता है) जो हमेशा एक व्यवहार्य विकल्प नहीं होता है।
19

1
@ म्यूटिनेटर: क्या आप बुरी तरह से डिज़ाइन की गई वस्तु से वारिस नहीं कर सकते हैं और इसे ठीक कर सकते हैं?
नील जी

2
या एनकैप्सुलेशन? बाह। मेरा मतलब है हां, बिल्कुल।
मूटिनेटर

4

कई भाषाओं में एक finallyस्टेटमेंट रिटर्न स्टेटमेंट के बाद भी चलता है। इसका मतलब है कि आप कुछ ऐसा कर सकते हैं:

try {
  // Do processing
  return result;
} finally {
  // Release resources
}

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

चाहे यह अच्छा हो या बुरा बहस के लिए है, लेकिन try {} finally {}हमेशा अपवाद से निपटने तक सीमित नहीं है।


0

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

तो मान लें कि हमारे पास छवि को लोड करने के लिए एक फ़ंक्शन है या उपयोगकर्ता की प्रतिक्रिया में ऐसा कुछ है जो लोड करने के लिए एक छवि फ़ाइल का चयन करता है, और यह सी और असेंबली में लिखा गया है:

यहाँ छवि विवरण दर्ज करें

मैंने कुछ निम्न-स्तर के कार्यों को छोड़ दिया, लेकिन हम देख सकते हैं कि मैंने विभिन्न श्रेणियों के कार्यों की पहचान की है, जो रंग-कोडित हैं, जो त्रुटि-हैंडलिंग के संबंध में उनकी जिम्मेदारियों पर आधारित है।

विफलता और रिकवरी के बिंदु

अब मैं "विफलताओं का संभावित बिंदु" (जो कि throw, अर्थात) और "त्रुटि पुनर्प्राप्ति और रिपोर्ट" फ़ंक्शन (जो कि catch, अर्थात) को कॉल करना मुश्किल था ।

उन कार्यों को हमेशा लिखने के लिए सही ढंग से पहले अपवाद हैंडलिंग उपलब्ध था एक समारोह है कि स्मृति को आबंटित करने में नाकाम रहने की तरह एक बाहरी विफलता में चला सकते हैं, सिर्फ एक लौट सकते हैं के बाद से तुच्छ थे NULLया 0या -1या एक वैश्विक त्रुटि कोड या इस संबंध में कुछ निर्धारित किया है। और त्रुटि पुनर्प्राप्ति / रिपोर्टिंग हमेशा आसान थी क्योंकि एक बार जब आपने कॉल स्टैक को एक ऐसे बिंदु पर काम किया था जहां यह पुनर्प्राप्त करने और विफलता की रिपोर्ट करने के लिए समझ में आया, तो आप बस त्रुटि कोड और / या संदेश लेते हैं और इसे उपयोगकर्ता को रिपोर्ट करते हैं। और इस पदानुक्रम के पत्ते पर स्वाभाविक रूप से एक फ़ंक्शन जो कभी नहीं हो सकता है, कभी भी असफल नहीं होता है कि यह भविष्य में कैसे बदल जाता है ( Convert Pixel) सही तरीके से लिखने के लिए मृत है (कम से कम त्रुटि से निपटने के संबंध में)।

त्रुटि प्रचार

हालांकि, मानव त्रुटि के लिए थकाऊ कार्यों में त्रुटि प्रसारकर्ता थे , जो सीधे विफलता में नहीं चले थे , लेकिन उन कार्यों को कहा जाता है जो पदानुक्रम में कहीं गहरे विफल हो सकते हैं। उस बिंदु पर, Allocate Scanlineएक विफलता को संभालना पड़ सकता है mallocऔर फिर एक त्रुटि को वापस कर सकता है Convert Scanlines, फिर Convert Scanlinesउस त्रुटि की जांच करनी होगी और उसे नीचे Decompress Image, फिर Decompress Image->Parse Image, और Parse Image->Load Image, और Load Imageउपयोगकर्ता-अंत कमांड में भेजना होगा जहां त्रुटि की रिपोर्ट की गई है। ।

यह वह जगह है जहाँ बहुत सारे मनुष्य गलतियाँ करते हैं क्योंकि यह केवल एक त्रुटि प्रसारकर्ता को जांचने में विफल होने के लिए ले जाता है और जब यह ठीक से त्रुटि को संभालने के लिए आता है, तो कार्य के पूरे पदानुक्रम के लिए त्रुटि को पास करना पड़ता है।

इसके अलावा, यदि त्रुटि कोड फ़ंक्शंस द्वारा लौटाए जाते हैं, तो हम बहुत अधिक क्षमता खो देते हैं, कहते हैं, हमारे कोडबेस के 90%, सफलता पर ब्याज के मूल्यों को वापस करने के लिए क्योंकि इतने सारे फ़ंक्शंस को एक त्रुटि कोड वापस करने के लिए अपना वापसी मूल्य आरक्षित करना होगा असफलता

मानव त्रुटि को कम करना: वैश्विक त्रुटि कोड

तो हम मानवीय त्रुटि की संभावना को कैसे कम कर सकते हैं? यहाँ पर मैं कुछ C प्रोग्रामरों के क्रोध को भी रोक सकता हूँ, लेकिन मेरी राय में एक तत्काल सुधार Open Open with जैसे वैश्विक त्रुटि कोड का उपयोग करना है glGetError। यह कम से कम कार्यों को सफलता पर ब्याज के सार्थक मूल्यों को लौटाने के लिए मुक्त करता है। इस थ्रेड को सुरक्षित और कुशल बनाने के तरीके हैं जहां त्रुटि कोड एक थ्रेड के लिए स्थानीयकृत है।

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

मानव त्रुटि को कम करना: अपवाद-हैंडलिंग

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

लेकिन यहां अपवाद-हैंडलिंग का मूल्य मैनुअल त्रुटि प्रसार के नियंत्रण प्रवाह पहलू से निपटने की आवश्यकता को मुक्त करना है। इसका मतलब है कि इसका मूल्य catchआपके कोडबेस में ब्लॉकों के एक बोटलोड को लिखने से बचने की क्षमता से जुड़ा हुआ है । उपरोक्त आरेख में, एक ही स्थान जिसमें एक catchब्लॉक होना चाहिए था , Load Image User Commandजहां त्रुटि रिपोर्ट की गई है। और कुछ नहीं आदर्श रूप से catchकुछ भी होना चाहिए क्योंकि अन्यथा यह थकाऊ और त्रुटि कोड हैंडलिंग के रूप में त्रुटि के रूप में शुरू हो रहा है।

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

संसाधन सफाई

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

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

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

बाहरी साइड इफेक्ट्स को उलट देना

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

यहाँ finallyनिश्चित रूप से सबसे सुंदर समाधानों में से एक है वहाँ की भाषा में समस्या का उत्परिवर्तन और साइड इफेक्ट्स के इर्द-गिर्द घूमना, क्योंकि अक्सर इस प्रकार के तर्क किसी विशेष कार्य के लिए बहुत विशिष्ट होते हैं और "रिसोर्स क्लीनअप" की अवधारणा को इतना अच्छा नहीं बनाते हैं। "। और मैं finallyइन मामलों में उदारतापूर्वक उपयोग करने की सलाह देता हूं ताकि यह सुनिश्चित किया जा सके कि आपका फ़ंक्शन उन भाषाओं में दुष्प्रभावों को उलट देता है जो इसका समर्थन करते हैं, भले ही आपको catchब्लॉक की आवश्यकता हो या न हो , और यदि आप मुझसे पूछें, तो अच्छी तरह से लिखे गए कोड की न्यूनतम संख्या होनी चाहिए catchब्लॉक, और सभी catchब्लॉक उन जगहों पर होना चाहिए जहां यह ऊपर के आरेख के साथ सबसे अधिक समझ में आता है Load Image User Command)।

सपना की भाषा

हालांकि, आईएमओ finallyसाइड इफेक्ट रिवर्सल के लिए आदर्श के करीब है , लेकिन काफी नहीं। हमें booleanसमय से पहले निकलने (फेंके गए अपवाद या अन्यथा से) के मामले में प्रभावी रूप से साइड इफेक्ट्स को रोल करने के लिए एक वैरिएबल लागू करने की आवश्यकता है , जैसे:

bool finished = false;
try
{
    // Cause external side effects.
    ...

    // Indicate that all the external side effects were
    // made successfully.
    finished = true; 
}
finally
{
    // If the function prematurely exited before finishing
    // causing all of its side effects, whether as a result of
    // an early 'return' statement or an exception, undo the
    // side effects.
    if (!finished)
    {
        // Undo side effects.
        ...
    }
}

अगर मैं कभी भी एक भाषा डिजाइन कर सकता हूं, तो इस समस्या को हल करने का मेरा सपना तरीका उपरोक्त कोड को स्वचालित करने के लिए होगा:

transaction
{
    // Cause external side effects.
    ...
}
rollback
{
    // This block is only executed if the above 'transaction'
    // block didn't reach its end, either as a result of a premature
    // 'return' or an exception.

    // Undo side effects.
    ...
}

... विध्वंसक के साथ स्थानीय संसाधनों की सफाई को स्वचालित करने के लिए, जिससे हमें केवल जरूरत है transaction, rollbackऔर catch(हालांकि मैं अभी भी जोड़ना चाहूंगा finally, कहते हैं, सी संसाधनों के साथ काम करना जो खुद को साफ नहीं करते हैं)। हालांकि, finallyएक booleanचर के साथ इस सीधी बनाने के लिए निकटतम चीज है जो मैंने पाया है कि अब तक मेरी सपनों की भाषा में कमी है। इसके लिए मैंने जो दूसरा सबसे सीधा हल खोजा है वह है C ++ और D जैसी भाषाओं में स्कोप गार्ड्स , लेकिन मैंने हमेशा स्कोप गार्ड्स को थोड़े अजीब तरीके से पाया है क्योंकि यह "रिसोर्स क्लीनअप" और "साइड इफेक्ट रिवर्सल" के विचार को दोष देता है। मेरी राय में वे एक अलग तरीके से निपटने के लिए बहुत विशिष्ट विचार हैं।

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

निष्कर्ष

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


-66

त्रुटियां / अपवाद को पकड़ना और उन्हें साफ-सुथरे तरीके से संभालना अत्यधिक अनिवार्य है भले ही अनिवार्य न हो।

मेरे कहने का कारण यह है क्योंकि मेरा मानना ​​है कि प्रत्येक डेवलपर को अपने आवेदन के व्यवहार को जानना चाहिए और उससे निपटना चाहिए अन्यथा उसने अपना काम विधिवत तरीके से पूरा नहीं किया है। ऐसी कोई स्थिति नहीं है जिसके लिए एक प्रयास-अंत में कोशिश-कैच-अंततः ब्लॉक को अवरुद्ध करता है।

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

सुनहरा नियम: हमेशा अपवाद को पकड़ें, क्योंकि अनुमान लगाने में समय लगता है


22
-1: जावा में, संसाधन जारी करने के लिए अंत में क्लॉज़ की आवश्यकता हो सकती है (जैसे फ़ाइल बंद करना या DB कनेक्शन जारी करना)। यह एक अपवाद को संभालने की क्षमता से स्वतंत्र है।
केविन क्लाइन

@kevincline, वह यह नहीं पूछ रहा है कि आखिरकार उपयोग करना है या नहीं ... सभी वह पूछ रहा है कि अपवाद को पकड़ना आवश्यक है या नहीं .... वह जानता है कि क्या कोशिश करते हैं, पकड़ते हैं और अंत में करते हैं ..... अंत में है सबसे आवश्यक हिस्सा, हम सभी जानते हैं कि और इसका उपयोग क्यों किया जाता है ....
पंकज उपाध्याय

63
@Pankaj: आपका जवाब पता चलता है कि एक catchखंड हमेशा मौजूद होना चाहिए, जब भी वहाँ है एक try। मेरे सहित अधिक अनुभवी योगदानकर्ताओं का मानना ​​है कि यह खराब सलाह है। आपका तर्क त्रुटिपूर्ण है। विधि युक्त tryएकमात्र ऐसा एकमात्र स्थान नहीं है जिसे अपवाद पकड़ा जा सकता है। यह कोड में पूरे क्लॉस को नकल करने के बजाय शीर्ष-स्तर से अपवादों को पकड़ने और रिपोर्ट करने की अनुमति देने के लिए अक्सर सबसे सरल और सबसे अच्छा होता है।
केविन क्लाइन

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

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