अंत में ब्लॉक में अपवाद फेंकता है


100

क्या finallyब्लॉक में फेंक दिए गए अपवादों को संभालने का एक सुंदर तरीका है ?

उदाहरण के लिए:

try {
  // Use the resource.
}
catch( Exception ex ) {
  // Problem with the resource.
}
finally {
   try{
     resource.close();
   }
   catch( Exception ex ) {
     // Could not close the resource?
   }
}

आप ब्लॉक में try/ से कैसे बचते हैं ?catchfinally

जवाबों:


72

मैं आमतौर पर इसे इस तरह से करता हूं:

try {
  // Use the resource.
} catch( Exception ex ) {
  // Problem with the resource.
} finally {
  // Put away the resource.
  closeQuietly( resource );
}

अन्य:

protected void closeQuietly( Resource resource ) {
  try {
    if (resource != null) {
      resource.close();
    }
  } catch( Exception ex ) {
    log( "Exception during Resource.close()", ex );
  }
}

4
हाँ, मैं एक बहुत ही समान मुहावरे का उपयोग करता हूं। लेकिन मैं उस के लिए एक समारोह नहीं बनाते हैं।
ऑस्कररेज़

9
यदि आप एक ही कक्षा में कुछ स्थानों पर मुहावरे का उपयोग करना चाहते हैं तो एक कार्य आसान है।
डैरन

नल की जांच बेमानी है। यदि संसाधन शून्य था, तो कॉलिंग विधि टूट गई है, इसे ठीक किया जाना चाहिए। इसके अलावा, यदि संसाधन शून्य है, तो संभवतः लॉग होना चाहिए। अन्यथा यह एक संभावित अपवाद के परिणामस्वरूप चुपचाप नजरअंदाज कर दिया जाता है।
डेव जार्विस

14
अशक्त के लिए चेक हमेशा बेमानी नहीं होता है। "संसाधन = नया FileInputStream (" file.txt ")" कोशिश की पहली पंक्ति के रूप में सोचें। इसके अलावा, यह सवाल पहलू उन्मुख प्रोग्रामिंग के बारे में नहीं था, जो बहुत से लोग उपयोग नहीं करते हैं। हालाँकि, यह अवधारणा कि अपवाद को केवल नजरअंदाज नहीं किया जाना चाहिए, लॉग स्टेटमेंट को दिखाते हुए सबसे कॉम्पैक्ट रूप से नियंत्रित किया गया था।
डैरन


25

मैं आमतौर पर closeQuietlyइन विधियों में से एक का उपयोग करता हूं org.apache.commons.io.IOUtils:

public static void closeQuietly(OutputStream output) {
    try {
        if (output != null) {
            output.close();
        }
    } catch (IOException ioe) {
        // ignore
    }
}

3
आप इस विधि को क्लोजेबल पब्लिक स्टैटिक शून्य के करीब सामान्य रूप से बना सकते हैं (क्लोजेबल क्लोजेबल) {
पीटर लॉरे

6
हां, क्लोजेबल अच्छा है। यह शर्म की बात है कि कई चीजें (जैसे जेडीबीसी संसाधन) इसे लागू नहीं करते हैं।
डारोन

22

यदि आप जावा 7, और resourceउपकरण का उपयोग कर रहे हैं AutoClosable, तो आप ऐसा कर सकते हैं (उदाहरण के रूप में InputStream का उपयोग करके):

try (InputStream resource = getInputStream()) {
  // Use the resource.
}
catch( Exception ex ) {
  // Problem with the resource.
}

8

संभवतः शीर्ष पर थोड़ा सा, लेकिन शायद उपयोगी हो अगर आप अपवादों को छोड़ रहे हैं और आप अपने तरीके से कुछ भी लॉग इन नहीं कर सकते हैं (उदाहरण के लिए क्योंकि यह एक पुस्तकालय है और आप कॉलिंग कोड अपवाद और लॉगिंग को संभालना चाहेंगे):

Resource resource = null;
boolean isSuccess = false;
try {
    resource = Resource.create();
    resource.use();
    // Following line will only run if nothing above threw an exception.
    isSuccess = true;
} finally {
    if (resource != null) {
        if (isSuccess) {
            // let close throw the exception so it isn't swallowed.
            resource.close();
        } else {
            try {
                resource.close();
            } catch (ResourceException ignore) {
                // Just swallow this one because you don't want it 
                // to replace the one that came first (thrown above).
            }
        }
    }
}

अद्यतन: मैंने इसे थोड़ा और अधिक देखा और किसी ऐसे व्यक्ति से एक बढ़िया ब्लॉग पोस्ट पाया, जिसने स्पष्ट रूप से मुझसे अधिक इस बारे में सोचा हो: http://illegalargumentexception.blogspot.com/2008/10/java-how-not-to-make -mess-of-stream.html वह एक कदम आगे जाता है और दो अपवादों को एक में जोड़ता है, जिसे मैं कुछ मामलों में उपयोगी होते हुए देख सकता था।


1
ब्लॉग लिंक के लिए +1। इसके अतिरिक्त, मैं कम से कम ignoreअपवाद को लॉग इन करता
हूं

6

Java 7 के अनुसार अब आपको अंततः ब्लॉक में स्पष्ट रूप से संसाधनों को बंद करने की आवश्यकता नहीं है, इसके बजाय आप try -with-syntax का उपयोग कर सकते हैं । ट्राई-विथ-रिसोर्स स्टेटमेंट एक ट्राइ स्टेटमेंट है जो एक या अधिक संसाधनों की घोषणा करता है। एक संसाधन एक वस्तु है जिसे कार्यक्रम के साथ समाप्त होने के बाद बंद किया जाना चाहिए। कोशिश-के साथ संसाधनों का बयान यह सुनिश्चित करता है कि प्रत्येक संसाधन बयान के अंत में बंद हो। कोई भी ऑब्जेक्ट जो java.lang.AutoCloseable को लागू करता है, जिसमें सभी ऑब्जेक्ट शामिल हैं जो java.io.Closeable को लागू करते हैं, एक संसाधन के रूप में उपयोग किया जा सकता है।

निम्नलिखित कोड मान लें:

try( Connection con = null;
     Statement stmt = con.createStatement();
     Result rs= stmt.executeQuery(QUERY);)
{  
     count = rs.getInt(1);
}

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

यह जानना भी महत्वपूर्ण है कि कोई भी अपवाद जो निकट विधियों को स्वचालित रूप से कहा जाता है, तब होता है। इन दबाए गए अपवादों को थ्रॉएबल क्लास में परिभाषित गेटस्पैप () विधि द्वारा प्राप्त किया जा सकता है ।

स्रोत: https://docs.oracle.com/javase/tutorial/essential/exception/tryResourceClose.html


यह अधूरा लगता है कि यह उत्तर इस दृष्टिकोण और ओपी के पोस्ट किए गए उदाहरण कोड के बीच व्यवहार के अंतर का उल्लेख नहीं करता है।
नाथन ह्यूजेस 16

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

यह एक अपवाद नहीं फेंकता है, निकट विधि को स्वचालित रूप से कहा जाता है दबा दिया जाता है।
सोरोश

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

3

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

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


2

एक समाधान, यदि दो अपवाद दो अलग-अलग वर्ग हैं

try {
    ...
    }
catch(package1.Exception err)
   {
    ...
   }
catch(package2.Exception err)
   {
   ...
   }
finally
  {
  }

लेकिन कभी-कभी आप इस दूसरी कोशिश को नहीं पकड़ सकते। जैसे एक धारा को बंद करने के लिए

InputStream in=null;
try
 {
 in= new FileInputStream("File.txt");
 (..)// do something that might throw an exception during the analysis of the file, e.g. a SQL error
 }
catch(SQLException err)
 {
 //handle exception
 }
finally
 {
 //at the end, we close the file
 if(in!=null) try { in.close();} catch(IOException err) { /* ignore */ }
 }

आपके मामले में यदि आपने "उपयोग" कथन का उपयोग किया है, तो उसे संसाधन को साफ करना चाहिए।
चक कॉनवे

मेरा बुरा, मैं मान रहा हूँ कि यह C # है।
चक कॉनवे

1

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

यदि आप एक अपवाद को फेंकने के लिए अंत में ब्लॉक की उम्मीद नहीं करते हैं और आपको नहीं पता है कि अपवाद को कैसे भी संभालना है (आप सिर्फ स्टैक ट्रेस ट्रेस करेंगे) कॉल स्टैक को अपवाद बबल दें (अंत में कोशिश-कैच को हटा दें) खंड मैथा)।

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

try {
    try {
        ...
    } catch (Exception ex) {
        ...
    } finally {
        ...
    }

    try {
        ...
    } catch (Exception ex) {
        ...
    } finally {
        ...
    }

    try {
        ...
    } catch (Exception ex) {
        ...
    } finally {
        ...
    }
} catch (Exception ex) {
    ...
}

2
-1 इसके लिए भी। क्या होगा अगर आप एक ही ब्लॉक में कई संसाधनों को बंद करने की कोशिश कर रहे हैं? यदि पहला संसाधन बंद करना विफल रहता है, तो अपवाद को फेंक दिए जाने के बाद अन्य खुले रहेंगे।
२०:१६ पर डाकू प्रोग्रामर

यही कारण है कि मैंने पॉल से कहा कि आप अपवादों को पकड़ सकते हैं यदि आप यह सुनिश्चित करना चाहते हैं कि आखिरकार ब्लॉक पूरा हो जाए। कृपया व्होल जवाब पढ़ें!
एडुआर्ड विर्च

1

बहुत विचार करने के बाद, मुझे निम्नलिखित कोड सबसे अच्छा लगता है:

MyResource resource = null;
try {
    resource = new MyResource();
    resource.doSomethingFancy();
    resource.close(); 
    resource = null;  
} finally {
    closeQuietly(resource)
}

void closeQuietly(MyResource a) {
    if (a!=null)
        try {
             a.close();
        } catch (Exception e) {
             //ignore
        }
}

वह कोड निम्नलिखित की गारंटी देता है:

  1. कोड समाप्त होने पर संसाधन को मुक्त कर दिया जाता है
  2. संसाधन को बंद किए बिना निकाले जाने वाले अपवादों को संसाधित किए बिना उपभोग नहीं किया जाता है।
  3. कोड दो बार संसाधन को बंद करने की कोशिश नहीं करता है, कोई भी अनावश्यक अपवाद नहीं बनाया जाएगा।

आप कॉल करने से भी बच सकते हैं resource.close (); संसाधन = कोशिश ब्लॉक में अशक्त है, कि आखिर ब्लॉक क्या हैं। यह भी ध्यान दें कि आप "कुछ कल्पना करते हुए" फेंकने वाले किसी अपवाद को नहीं संभालते हैं, जो वास्तव में, मुझे लगता है कि मैं बेहतर पसंद करता हूं, स्टैक के नीचे एक उच्चतर एप्लिकेशन स्तर पर अवसंरचनात्मक अपवादों को संभालने के लिए।
पॉल

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

0

यदि आप शुरू करने के लिए त्रुटि की स्थिति से बचने के लिए परीक्षण कर सकते हैं।

try{...}
catch(NullArgumentException nae){...}
finally
{
  //or if resource had some useful function that tells you its open use that
  if (resource != null) 
  {
      resource.Close();
      resource = null;//just to be explicit about it was closed
  }
}

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


परीक्षण त्रुटि की स्थिति सामान्य रूप से एक अच्छा अभ्यास है, सिर्फ इसलिए कि अपवाद महंगे हैं।
डर्क वोल्मार

"डिफेंसिव प्रोग्रामिंग" एक आउटमोडेड प्रतिमान है। फूला हुआ कोड जो सभी त्रुटि स्थितियों के लिए परीक्षण से उत्पन्न होता है, अंततः इससे हल करने की तुलना में अधिक समस्याएं पैदा करता है। TDD और हैंडलिंग अपवाद यह है कि आधुनिक दृष्टिकोण IMHO
जो सोल-लाने वाला

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

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

@ ओटलॉ - आप मेरी बात याद कर रहे हैं यदि क्लोज़ एक अपवाद को फेंक देता है, और संसाधन खुला है तो कैप्चर करके और अपवाद को दबाकर मैं समस्या को कैसे ठीक करूँ? इसलिए मैंने इसे प्रचारित क्यों किया (इसके काफी दुर्लभ होने के साथ मैं इसे अभी भी खोल सकता हूं)।
केन हेंडरसन

0

आप इसे दूसरी विधि में रिफ्लेक्टर कर सकते हैं ...

public void RealDoSuff()
{
   try
   { DoStuff(); }
   catch
   { // resource.close failed or something really weird is going on 
     // like an OutOfMemoryException 
   }
}

private void DoStuff() 
{
  try 
  {}
  catch
  {
  }
  finally 
  {
    if (resource != null) 
    {
      resource.close(); 
    }
  }
}

0

मैं आमतौर पर ऐसा करता हूं:

MyResource r = null;
try { 
   // use resource
} finally {   
    if( r != null ) try { 
        r.close(); 
    } catch( ThatSpecificExceptionOnClose teoc ){}
}

Rationale: अगर मैं संसाधन के साथ कर रहा हूं और मेरे पास एकमात्र समस्या है जो इसे बंद कर रही है, तो इसके बारे में बहुत कुछ नहीं है। यह वैसे भी पूरे धागे को मारने के लिए समझ में नहीं आता है अगर मैं वैसे भी संसाधन के साथ कर रहा हूँ।

यह उन मामलों में से एक है जब कम से कम मेरे लिए, उस चेक किए गए अपवाद को अनदेखा करना सुरक्षित है।

आज तक मुझे इस मुहावरे का उपयोग करने में कोई समस्या नहीं हुई।


यदि आप भविष्य में कुछ लीक पाते हैं, तो मैं इसे लॉग इन करूँगा। इस तरह से आपको पता चल जाएगा कि वे कहां से आ रहे हैं (नहीं)
Egwor

@Egwor। मैं आपसे सहमत हुँ। यह सिर्फ कुछ त्वरित निस्तब्धता थी। मैं इसे भी लॉग करता हूं और एक कैच का इस्तेमाल करता हूं। कुछ अपवाद के साथ किया जा सकता है :)
OscarRyz

0
try {
    final Resource resource = acquire();
    try {
        use(resource);
    } finally {
        resource.release();
    }
} catch (ResourceException exx) {
    ... sensible code ...
}

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


5
क्या होगा यदि उपयोग (संसाधन) अपवाद A को फेंकता है और फिर resource.release () अपवाद B को फेंकता है? अपवाद ए खो गया है ...
डैरन

0

सबसे अच्छे उत्तरResource से बदल रहा हैCloseable

धाराएं लागू होती हैं Closeableइस प्रकार आप सभी धाराओं के लिए विधि का पुन: उपयोग कर सकते हैं

protected void closeQuietly(Closeable resource) {
    if (resource == null) 
        return;
    try {
        resource.close();
    } catch (IOException e) {
        //log the exception
    }
}

0

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

IOException ioException = null;
try {
  outputStream.write("Something");
  outputStream.flush();
} catch (IOException e) {
  throw new ExportException("Unable to write to response stream", e);
}
finally {
  try {
    outputStream.close();
  } catch (IOException e) {
    ioException = e;
  }
}
if (ioException != null) {
  throw new ExportException("Unable to close outputstream", ioException);
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.