क्या कभी भी एक खाली कैच स्टेटमेंट होना ठीक है?


58

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


आखिर क्या हुआ?
क्रिस

2
btw - यह पिछले साल SO पर पूछा गया था: stackoverflow.com/questions/1234343/…
वॉरेन

17
यह कम से कम एक टिप्पणी होनी चाहिए कि यह खाली क्यों है।
पीटरचेन

जवाबों:


77

मैं यह हर समय डी में रूपांतरण त्रुटियों जैसी चीजों के साथ करता हूं:

import std.conv, std.stdio, std.exception;

void main(string[] args) {  
    enforce(args.length > 1, "Usage:  foo.exe filename");

    double[] nums;

    // Process a text file with one number per line into an array of doubles,
    // ignoring any malformed lines.
    foreach(line; File(args[1]).byLine()) {
        try {
            nums ~= to!double(line);
        } catch(ConvError) {
            // Ignore malformed lines.
        }
    }

    // Do stuff with nums.
}

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

संपादित करें: मैं इस बात पर भी जोर देना चाहता हूं कि यदि आप ऐसा कुछ करने जा रहे हैं, तो आपको केवल उस विशेष अपवाद को पकड़ने के लिए सावधान रहना चाहिए जिसे आप अनदेखा करना चाहते हैं। एक सादा पुराना catch {}करना लगभग हमेशा एक बुरी बात है।


15
स्पष्टीकरण टिप्पणी के लिए +1।
माइकल के

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

मैं परिचित डी नहीं हूं, लेकिन मुझे लगता है कि बूल ट्रायपर्स (स्ट्रिंग लाइन, आउट डबल वैलेटो पर्स) जैसा कुछ करना संभव है, जो क्लीनर हो सकता है।
15

4
वाह, कोई है जो वास्तव में डी का उपयोग करता है! :-P
जेम्स मैकनेलिस

4
जैसे @ मिचेल कहते हैं - यह काफी खाली नहीं है क्योंकि आपको टिप्पणी मिली है; अगर कोई स्टेटमेंट नहीं है तो "इस कैच को जानबूझकर खाली छोड़ना" टिप्पणी को जोड़ना अनिवार्य होगा
STW

50

एक उदाहरण जहां मुझे लगता है कि कुछ भी किए बिना केवल अपवाद को निगल जाना ठीक है, यहां तक ​​कि अपवाद को लॉग करना, लॉगिंग कोड के अंदर ही है।

यदि आपने कुछ लॉग करने की कोशिश की और अपवाद मिला तो बहुत कुछ नहीं है जो आप इसके बारे में कर सकते हैं:

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

यह आपको चुपचाप निगलने के "कम से कम बुराई" विकल्प के साथ छोड़ देता है, जिससे एप्लिकेशन को अपना मुख्य काम जारी रखने की अनुमति मिलती है, लेकिन इसके निवारण की क्षमता से समझौता करता है।


10
महान बिंदु। डिबगिंग कोड को डीबग करना हमेशा एक चुनौती होती है।
देवसोलो 14

7
यह, एक लाख बार। खासकर जब आप विचार करते हैं कि यदि आप लॉग इन कर रहे हैं, तो आप भयानक स्थिति में हो सकते हैं; आप स्मृति से बाहर हो सकते हैं, दुर्घटनाग्रस्त हो सकते हैं, कुछ भी हो सकते हैं। इस बिंदु पर, जब आप एक त्रुटि लॉग कर रहे हैं, और यह विफल रहता है, तो करने के लिए केवल जिम्मेदार चीज कुछ भी नहीं है; आपको इस बात की कोई गारंटी नहीं है कि आप जो कुछ भी आजमाते हैं वह इसे और खराब नहीं करेगा।
GWLlosa

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

@ तंगुरेना यदि यह अक्सर अशक्त है तो उसे संभालें, झटका न दें। C # में मैं अक्सर ऐसी चीजों को पहरा देता हूँ ?? "";
लोरेन Pechtel

8

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

यदि आप ऐसा कर रहे हैं, तो एक टिप्पणी शामिल करें। हमेशा कुछ भी टिप्पणी करें जो बग की तरह दिखता है (एक switchबयान में रिक्तता , खाली catchब्लॉक, एक स्थिति में असाइनमेंट)।

आप यह तर्क दे सकते हैं कि यह अपवादों का उचित उपयोग नहीं है, लेकिन यह एक और सवाल है।


6

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

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

  • अपवाद के बारे में कुछ मत करो। इसे एक अलग परत द्वारा पकड़ा और संभाला जाएगा
  • इसे पकड़ें और सुधारात्मक कार्रवाई करें।
  • इसे पकड़ें, कुछ करें, लेकिन एक और परत को संभालने के लिए इसे फिर से फेंक दें

यह वास्तव में कुछ भी नहीं करने के लिए कोई जगह नहीं छोड़ता है, खाली catchब्लॉक।

EDD TO ADD : मान लें कि आप किसी ऐसी भाषा में प्रोग्रामिंग कर रहे हैं, जहां अपवाद फेंकना प्रोग्राम लॉजिक (विकल्पों में से एक goto) को नियंत्रित करने का सामान्य तरीका है । फिर catchइस भाषा में लिखे गए प्रोग्राम में एक खाली elseब्लॉक पारंपरिक भाषा में खाली ब्लॉक (या elseबिल्कुल भी ब्लॉक नहीं ) की तरह है। हालांकि, मेरा मानना ​​है कि यह C #, जावा या C ++ विकास समुदायों द्वारा अनुशंसित प्रोग्रामिंग शैली नहीं है।


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

+1 पहचानने के लिए कि एक खाली कैच ब्लॉक प्रवाह नियंत्रण के लिए अपवादों के उपयोग का संकेत दे सकता है।
जॉन एम गेंट

प्रोग्रामिंग लॉजिक के अपवादों का उपयोग करना आमतौर पर बुरा व्यवहार माना जाता है। लेकिन, आश्चर्यजनक रूप से (अपवादों के खिलाफ मेरा मूल तर्क) अपवाद ध्यान देने योग्य प्रदर्शन को प्रभावित नहीं करते हैं। Codeproject.com/KB/exception/ExceptionPerformance.aspx देखें ।
इवान प्लाइस

6

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

try {
   bytes[] hw = "Hello World".getBytes("UTF-8");
}
catch(UnsupportedCodingException e) {
}

जावा प्लेटफॉर्म के प्रत्येक कार्यान्वयन के लिए निम्न मानक वर्णों का समर्थन करना आवश्यक है।

...

UTF-8

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


1
इस तरह के मामलों में मुझे यह सुनिश्चित करने के लिए जोड़ा throw new Error(e)जाएगा कि मुझे कुछ भी याद नहीं है (या वास्तव में टूटे हुए प्लेटफॉर्म की रिपोर्ट करें)।
हाले क्नास्ट

@ हेलकंस्ट हां। इसकी पूरी चर्चा यहाँ की गई है: softwareengineering.stackexchange.com/questions/122233/…
user281377

5

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

हालांकि, मैं अक्सर ऐसा करता हूं जब मैं तार को पार्स कर रहा हूं और संख्याओं में परिवर्तित कर रहा हूं (विशेषकर मैपिंग परियोजनाओं में जो कि उपयोग-एक बार और दूर की विविधता को फेंकते हैं)।

boolean isNonZeroNumber = false;

try {
   if(StringUtils.isNotBlank(s) && new BigDecimal(s).compareTo(BigDecimal.ZERO) != 0) {
     b = true;
   }
} catch(NumberFormatException e) {
//swallow this exception; b stays false.
}

return b;

3

कुछ मामलों में, अपवाद बिल्कुल भी असाधारण नहीं है; वास्तव में, यह अपेक्षित है। इस उदाहरण पर विचार करें:

    /* Check if the process is still alive; exitValue() throws an exception if it is */
    try {
        p.exitValue();
        processPool.remove(p);
    }
    catch (IllegalThreadStateException e) { /* expected behaviour */ }

चूँकि java.lang.Process () में isAlive () मेथड नहीं है, यह जाँचने के एकमात्र तरीके के बारे में कि क्या यह अभी भी जीवित है, एक्ज़िटवैल्यू () को कॉल करना है, जो कि एक IllegalThreadStateEception को फेंकता है यदि प्रक्रिया अभी भी चल रही है।


2

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

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

कभी-कभी, उदाहरण के लिए एपीआई परतों पर, आप अपवादों को अतीत में रहने नहीं देना चाहते हैं या नहीं पा सकते हैं, इसलिए उस स्थिति में, मैं सबसे सामान्य प्रयास करने और पकड़ने की कोशिश करता हूं, फिर उन पर लॉग ऑन करें। एक बार फिर, कम से कम डिबग / निदान सत्र को मौका दें।

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


2

आईएमओ एक जगह है जहां खाली कैच स्टेटमेंट ठीक हैं। परीक्षण मामलों में जहां आप एक अपवाद की उम्मीद करते हैं:

try
{
   DoSomething(); //This should throw exception if everything works well
   Assert.Fail('Expected exception was not thrown');
}
catch(<whatever exception>)
{
    //Expected to get here
}

+1, मुझे नफरत है कि मैं ऐसा करता हूं लेकिन यह JUnit में काम करता है
साल

@ साल्स: @ टेस्ट (अपेक्षित = अपवाद.क्लास) के बारे में क्या?
ysolik

@ysolik, बुरी आदत
साल

1
@ ससल: वह बुरी आदत क्यों है?
एडम लेअर

ummmm। यूनिट टेस्टिंग फ्रेमवर्क के साथ ऐसा करने के तरीके हैं। पूर्व। NUnit। ऐसे कुछ मामले हैं जहां परीक्षण करना कि कुछ अनुमानित रूप से विफल होता है उपयोगी हो सकता है। हालांकि, मैं इसे प्रोडक्शन कोड में कभी नहीं करूंगा।
इवान प्लाइस

2

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


1

मुझे विश्वास नहीं है कि अपवाद होने पर कुछ स्तर की सतर्कता नहीं होती - क्या कोड को बेहतर बनाने के लिए प्रोग्रामिंग के लक्ष्यों में से एक नहीं होना चाहिए? यदि कोई अपवाद समय का 10% होता है, और आप इसके बारे में कभी नहीं जानते हैं, तो अपवाद हमेशा बुरा या बुरा होगा।

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

यदि यह एक सौम्य अपवाद है, तो मैं अपने लकड़हारे को एक कॉल करता हूं ।ebug () विधि; अन्यथा, Logger.Error () (और (शायद) फेंक)।

try
{
   doWork();
}
catch(BenignException x)
{
  _log.Debug("Error doing work: " + x.Message);
}

वैसे, मेरे लकड़हारा के मेरे कार्यान्वयन में, .Debug () पद्धति से कॉल करना केवल तभी लॉग करेगा जब मैं अपना App.Config फ़ाइल निर्दिष्ट करता हूं कि प्रोग्राम निष्पादन लॉग स्तर डीबग मोड में है।


क्या होगा अगर _log.Debug एक अपवाद (जो भी कारण के लिए) फेंकता है?
जॉनएल

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

1

अस्तित्व की जाँच एक अच्छा उपयोग मामला है:

// If an exception happens, it doesn't matter. Log the initial value or the new value

function logId(person) {
    let id = 'No ID';
    try {
        id = person.data.id;
    } catch {}
    console.log(id);
}

एक और मामला है जब एक finallyखंड का उपयोग किया जाता है:

 function getter(obj){}

 function objChecker()
   {
   try
     {
     /* Check argument length and constructor type */
     if (getter.length === 1 && getter.constructor === Function)
       {
       console.log("Correct implementation");
       return true;
       }
     else
       {
       console.log("Wrong implementation");
       return false;
       }
     }
   catch(e)
     {
     }
   finally
     {
     console.log(JSON.stringify(getter))
     }
   }

 // Test the override of the getter method 
 getter = getter;
 objChecker();
 getter = [];
 objChecker();
 getter = {};
 objChecker();
 getter = RegExp;
 objChecker();
 getter = Function;
 objChecker();

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

संदर्भ


एक और उदाहरण: नोडज में, fexexists पद्धति (जो सच या गलत लौटाती है) को पदावनत किया जाता है ( नोडjs.org/dist/latest-v10.x/docs/api/… ) facaccess के पक्ष में जो एक अपवाद को फेंकता है। मामला एक फाइल मौजूद नहीं है। यदि कोई केवल कुछ करना चाहता है यदि फ़ाइल मौजूद है, तो पकड़ क्लॉज पूरी तरह से अनावश्यक है।
systemovich

0

एकमात्र समय जब मुझे वास्तव में कुछ ऐसा करने की आवश्यकता होती है, यह कंसोल ऐप के लिए लॉगिंग क्लास के साथ था। एक शीर्ष-स्तरीय वैश्विक कैच हैंडलर था जिसने STDOUT में त्रुटि का उत्सर्जन किया, त्रुटि को एक फ़ाइल में लॉग इन किया, फिर ऐप को> 0 त्रुटि कोड के साथ बंद कर दिया।

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

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

यह खाली है, यह बताते हुए बेशक एक टिप्पणी है।

(मैं यह पहले पोस्ट करने जा रहा था, मुझे बस गुमनामी में बह जाने का डर था। चूंकि मैं अकेला नहीं हूं, हालांकि)


0

यह उस स्थिति में ठीक है जब कुछ अनुक्रम को क्रियान्वित किया जाना चाहिए चाहे वह अंत में रखा गया सबसे महत्वपूर्ण टुकड़ा क्यों न हो।

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


इसका मतलब यह नहीं है कि आप कुछ भी नहीं करते हैं, बस आप जो करते हैं वह प्रवाह को समाप्त नहीं करता है। अपने अपवादों को पकड़ें, उन्हें स्मृति में सहेजें (कोई डिस्क विलंब न लिखें), फिर एक अंतिम बयान में शक्ति को मार दें। फिर जो जानकारी बची है उसे आप करें।
लोरेन Pechtel

0

किसी त्रुटि से उबरने के लिए सिस्टम संसाधनों को बंद करना

उदाहरण के लिए। यदि आप उस पृष्ठभूमि में एक सेवा चला रहे हैं जो उपयोगकर्ता को प्रतिक्रिया प्रदान नहीं करती है, तो आप उपयोगकर्ता को त्रुटि का संकेत नहीं देना चाहते हैं, लेकिन आपको एक सुंदर तरीके से उपयोग किए जा रहे संसाधनों को बंद करने की आवश्यकता है।

try
{
    // execution code here
}
catch(Exception e)
{
    // do nothing here
}
finally
{
    // close db connection
    // close file io resource
    // close memory stream
    // etc...
}

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

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