क्या थ्रोबल को पकड़ना एक बुरा अभ्यास है?


106

क्या यह पकड़ने के लिए एक बुरा अभ्यास है Throwable?

उदाहरण के लिए कुछ इस तरह से:

try {
    // Some code
} catch(Throwable e) {
    // handle the exception
}

क्या यह एक बुरा अभ्यास है या हमें यथासंभव विशिष्ट होना चाहिए?


जवाबों:


104

आपको यथासंभव विशिष्ट होने की आवश्यकता है। अन्यथा अप्रत्याशित कीड़े इस तरह से दूर हो सकते हैं।

इसके अलावा, Throwableकवर के Errorरूप में अच्छी तरह से और आमतौर पर वापसी का कोई मतलब नहीं है । आप इसे पकड़ना / संभालना नहीं चाहते हैं, आप चाहते हैं कि आपका कार्यक्रम तुरंत मर जाए ताकि आप इसे ठीक से ठीक कर सकें।


38
ऐसी स्थितियाँ हैं जहाँ त्रुटि पकड़ना और जारी रखना उचित है। Ex: एक सर्वलेट में, यदि आप एक OutOfMemoryError को जोड़ते हैं क्योंकि एक विशिष्ट अनुरोध सभी मेमोरी खाने के लिए होता है, तो आप कोशिश कर सकते हैं कि अनुरोध जारी रहने के बाद ऑब्जेक्ट GC हो जाएगा। वही एक जोरदार त्रुटि के लिए जाता है। आप किसी एप्लिकेशन को बंद नहीं करते क्योंकि अनुरोध में कुछ गलत हो गया था।
गवी

7
आपको कैसे पता चलेगा कि क्या आवंटित किया गया था और क्या कुछ पहले नहीं था? एक बार J2EE कंटेनर जैसे कि Tomcat या JBoss के अंदर भी सभी दांव बंद हो जाते हैं।
bmauter

10
हमारे पास NoSuchMethodError है और शुक्र है कि सर्वर बंद करने से हमारे सभी ग्राहकों को बाहर नहीं निकाला क्योंकि यह तैनाती के दो सप्ताह बाद हुआ था। अर्थात। हमारे पास हमेशा एक कैच है जो थ्रोबल को पकड़ता है और ग्राहक को त्रुटि को संभालने और भेजने के लिए एक सर्वोत्तम प्रयास करता है। आखिरकार, बहुत सारे प्रकार की त्रुटि होती है जो पुनर्प्राप्त करने योग्य होती है कि यह केवल 1000 ग्राहकों में से 1 को प्रभावित कर सकती है।
डीन हिलर

10
" आप चाहते हैं कि आपका कार्यक्रम तुरंत मर जाए ताकि आप इसे ठीक से ठीक कर सकें " => यदि आपका कार्यक्रम मर जाता है, तो आप कैसे जानते हैं कि क्या हुआ? समस्या को लॉग करने के लिए थ्रोबल / एरर को पकड़ना एक उचित काम है ...
assylias

3
@assylias एक स्टैंड-अलोन एप्लिकेशन, stderr के लिए एक घातक त्रुटि फेंक देगा।
फिलिप व्हाइटहाउस

36

यह विचार अच्छा नहीं है। वास्तव में, यहां तक ​​कि पकड़ना Exceptionआमतौर पर एक बुरा विचार है। आइए एक उदाहरण पर विचार करें:

try {
    inputNumber = NumberFormat.getInstance().formatNumber( getUserInput() );
} catch(Throwable e) {
    inputNumber = 10; //Default, user did not enter valid number
}

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

अपवाद को पकड़ने के साथ एक समान समस्या होती है। हो सकता है getUserInput()कि एक InterruptException, या एक अनुमति के कारण विफल रहा है जबकि परिणाम, या अन्य विफलताओं के सभी प्रकार के लॉग इन करने की कोशिश कर रहे अपवाद से इनकार कर दिया। आपके पास कोई विचार नहीं है कि क्या गलत हुआ, क्योंकि इसके कारण, आपको यह भी पता नहीं है कि समस्या को कैसे ठीक किया जाए।

आपके पास तीन बेहतर विकल्प हैं:

1 - सटीक अपवाद को पकड़ो जो आप जानते हैं कि कैसे संभालना है:

try {
    inputNumber = NumberFormat.getInstance().formatNumber( getUserInput() );
} catch(ParseException e) {
    inputNumber = 10; //Default, user did not enter valid number
}

2 - आपके द्वारा चलाए जा रहे किसी भी अपवाद को रोकें और संभालना नहीं जानते:

try {
    doSomethingMysterious();
} catch(Exception e) {
    log.error("Oh man, something bad and mysterious happened",e);
    throw e;
}

3 - अंत में ब्लॉक का उपयोग करें ताकि आपको पुनर्विचार करने के लिए याद न करना पड़े:

 Resources r = null;
 try {
      r = allocateSomeResources();
      doSomething(r);
 } finally {
     if(r!=null) cleanUpResources(r);
 }

4
+1 यह बताते हुए कि अपवाद को पकड़ना भी अच्छा नहीं है। कम से कम एक थ्रेडइंटरप्टेड एक्ससेप्शन है जिसे विशेष देखभाल की आवश्यकता होती है (संक्षेप में - इसे पकड़ने के बाद, आपको थ्रेड की बाधित स्थिति को 'सही' पर सेट करना होगा)
किरिल गमाज़कोव

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

अगर मैं इसे नहीं पकड़ता हूं तो मुझे कैसे पता चलेगा कि कोई एरर / थ्रोबेबल है? मुझे लॉग में कुछ भी दिखाई नहीं दिया। जावा ईई ऐप। बस बिताए दिन यह नहीं जानते कि जब तक मैंने यह कैच नहीं जोड़ा तब तक क्या समस्या थी।
फिलिप रेगो

2
मैं विकल्प # 2 को बुरी प्रथा मानता हूं। लॉग और रीथ्रो के साथ 10 जंजीर कॉल की कल्पना करें। यदि आप लॉग फ़ाइल को देखते हैं, तो आप खुश नहीं होंगे। अपवाद को लॉग किया जाता है 10 बार लॉग को पढ़ना बहुत कठिन होता है। IMHO करना बेहतर है throw new Exception("Some additional info, eg. userId " + userId, e);। यह 10 कारणों के साथ एक अच्छे अपवाद में लॉग इन किया जाएगा।
पेट्र Petजदस्क़ी

21

यह भी ध्यान रखें कि जब आप पकड़ते हैं Throwable, तो आप भी पकड़ सकते हैं InterruptedExceptionजिसके लिए एक विशेष उपचार की आवश्यकता होती है। अधिक जानकारी के लिए InterruptedException से निपटना देखें ।

यदि आप केवल अनियंत्रित अपवादों को पकड़ना चाहते हैं, तो आप इस पैटर्न पर भी विचार कर सकते हैं

try {
   ...
} catch (RuntimeException exception) {
  //do something
} catch (Error error) {
  //do something
}

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


14

त्रुटि वर्ग के javadoc से सीधे (जो इन्हें न पकड़ने की सलाह देता है):

 * An <code>Error</code> is a subclass of <code>Throwable</code> 
 * that indicates serious problems that a reasonable application 
 * should not try to catch. Most such errors are abnormal conditions. 
 * The <code>ThreadDeath</code> error, though a "normal" condition,
 * is also a subclass of <code>Error</code> because most applications
 * should not try to catch it. 

 * A method is not required to declare in its <code>throws</code> 
 * clause any subclasses of <code>Error</code> that might be thrown 
 * during the execution of the method but not caught, since these 
 * errors are abnormal conditions that should never occur. 
 *
 * @author  Frank Yellin
 * @version %I%, %G%
 * @see     java.lang.ThreadDeath
 * @since   JDK1.0

13

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

यदि आप वास्तव में अपवाद को नहीं संभाल सकते हैं तो यह एक बुरा अभ्यास है। बेहतर तरीके से "थ्रो" को जोड़ने के लिए सिर्फ पकड़ने और फिर से फेंकने की तुलना में विधि हस्ताक्षर में इसे RuntimeException और पुनः-फेंक में लपेटें।


10
पूरी तरह से सहमत हैं - सभी Throwableउदाहरणों को संभालने के लिए बिल्कुल वैध मामले हैं - उदाहरण के लिए कस्टम अपवाद लॉगिंग।
यूरी नकोनचैनी

9

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

हालाँकि, इन परिस्थितियों में सबसे अच्छा होगा कि सभी थ्रोबेबल्स की बजाय केवल लाइब्रेरी द्वारा फेंकी गई विशिष्ट त्रुटियों को निर्दिष्ट करें।


12
या एक बेहतर लिखित पुस्तकालय का उपयोग करें?
राडवल्ड

6
वास्तव में, यदि आपके पास विकल्प है ;-)
डीएनए

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

6

थ्रोएबल सभी वर्गों के लिए आधार वर्ग है जिसे फेंका जा सकता है (केवल अपवाद नहीं)। अगर आप आउटऑफ़मेरीऑरर या कर्नेलएर्रर को पकड़ते हैं तो बहुत कम आप कर सकते हैं (देखें कि java.lang.Error कब पकड़ना है? )

अपवादों को पकड़ना पर्याप्त होना चाहिए।


5

यह आपके तर्क पर निर्भर करता है या आपके विकल्पों / संभावनाओं के लिए अधिक विशिष्ट होता है। यदि कोई विशिष्ट अपवाद है जो आप संभवतः सार्थक तरीके से प्रतिक्रिया कर सकते हैं, तो आप इसे पहले पकड़ सकते हैं और ऐसा कर सकते हैं।

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

आमतौर पर पहला मामला पकड़ में आता है और आप फेंकने योग्य नहीं होते। लेकिन अभी भी बहुत सारे मामले हैं जहां इसे पकड़ना ठीक काम करता है।


4

यद्यपि यह एक बहुत ही खराब प्रथा के रूप में वर्णित है, आप कभी-कभी दुर्लभ मामलों को पा सकते हैं कि यह न केवल उपयोगी है, बल्कि अनिवार्य भी है। यहाँ दो उदाहरण हैं।

एक वेब एप्लिकेशन में जहां आपको उपयोगकर्ता को एक अर्थ पूर्ण त्रुटि पृष्ठ दिखाना होगा। यह कोड सुनिश्चित करता है कि ऐसा होता है क्योंकि यह try/catchआपके सभी अनुरोध हैंडेलर्स (सर्वलेट्स, स्ट्रट्स एक्शन या किसी भी कंट्रोलर ...) के आसपास एक बड़ा है ।

try{
     //run the code which handles user request.
   }catch(Throwable ex){
   LOG.error("Exception was thrown: {}", ex);
     //redirect request to a error page. 
 }

}

एक अन्य उदाहरण के रूप में, विचार करें कि आपके पास एक सेवा वर्ग है जो फंड ट्रांसफर व्यवसाय का कार्य करता है। TransferReceiptयदि स्थानांतरण किया जाता है या NULLयदि यह नहीं हो सका तो यह विधि वापस आती है ।

String FoundtransferService.doTransfer( fundtransferVO);

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

for(FundTransferVO fundTransferVO : fundTransferVOList){
   FoundtransferService.doTransfer( foundtransferVO);
}

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

for(FundTransferVO fundTransferVO : fundTransferVOList){
    FoundtransferService.doTransfer( foundtransferVO);
 }catch(Throwable ex){
    LOG.error("The transfer for {} failed due the error {}", foundtransferVO, ex);
  }
}

आप यह देखने के लिए बहुत सारे ओपन सोर्स प्रोजेक्ट ब्राउज़ कर सकते हैं कि throwableयह वास्तव में कैश्ड और हैंडल है। उदाहरण के लिए यहाँ एक खोज है tomcat, struts2और primefaces:

https://github.com/apache/tomcat/search?utf8=%E2%9C%93&q=catch%28Throwable https://github.com/apache/struts/search?utf8-%E2%9C%93&q=catch % 28Throwable https://github.com/primefaces/primefaces/search?utf8=%E2%9C%93&q=catch%28Throwable


1
इन लिंक्स में कोड देखा। थ्रोबल केवल वह नहीं है जो पकड़ा गया है! थ्रोबेबल से पहले पकड़े गए अन्य अपवाद भी हैं।
डेवलपर

@ डेवलपर throwable
101

4

सवाल थोड़ा अस्पष्ट है; क्या आप पूछ रहे हैं "क्या यह पकड़ने के लिए ठीक है Throwable", या "क्या इसे पकड़ना ठीक है Throwableऔर कुछ नहीं करना है"? यहाँ कई लोगों ने उत्तर दिया, लेकिन यह एक पक्ष है; समय के 99% आप नहीं करना चाहिए "उपभोग" या अपवाद को छोड़ दे, आप को पकड़ने रहे हैं कि क्या Throwableया IOExceptionया जो कुछ भी।

यदि आप अपवाद का प्रचार करते हैं, तो उत्तर (जैसे कई प्रश्नों के उत्तर) "यह निर्भर करता है" है। यह इस बात पर निर्भर करता है कि आप अपवाद के साथ क्या कर रहे हैं — आप इसे क्यों पकड़ रहे हैं।

यदि आप Throwableकोई त्रुटि चाहते हैं तो इसका एक अच्छा उदाहरण है कि किसी प्रकार की सफाई प्रदान करना । उदाहरण के लिए, JDBC में, यदि लेन-देन के दौरान कोई त्रुटि होती है, तो आप लेन-देन वापस करना चाहेंगे:

try {
  
} catch(final Throwable throwable) {
  connection.rollback();
  throw throwable;
}

ध्यान दें कि अपवाद को खारिज नहीं किया गया है, लेकिन प्रचारित किया गया है।

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


1

आम तौर पर बोलते हुए आप कैच से बचना चाहते हैं Errorलेकिन मैं दो विशिष्ट मामलों के बारे में सोच सकता हूं जहां ऐसा करना उचित है:

  • आप त्रुटियों के जवाब में एप्लिकेशन को बंद करना चाहते हैं, खासकर AssertionError जो अन्यथा हानिरहित है।
  • क्या आप ExecutorService.submit () के समान थ्रेड-पूलिंग तंत्र लागू कर रहे हैं, जिससे आपको उपयोगकर्ता को अपवादों को अग्रेषित करना होगा ताकि वे इसे संभाल सकें।

0

अगर हम फेंकने योग्य का उपयोग करते हैं , तो यह त्रुटि को भी कवर करता है और यही है।

उदाहरण।

    public class ExceptionTest {
/**
 * @param args
 */
public static void m1() {
    int i = 10;
    int j = 0;
    try {
        int k = i / j;
        System.out.println(k);
    } catch (Throwable th) {
        th.printStackTrace();
    }
}

public static void main(String[] args) {
    m1();
}

}

आउटपुट:

java.lang.ArithmeticException: / by zero
at com.infy.test.ExceptionTest.m1(ExceptionTest.java:12)
at com.infy.test.ExceptionTest.main(ExceptionTest.java:25)

0

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


-1

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

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

public Integer addNumbers(Integer a, Integer b) {
    Integer c = a + b;          //This will throw a NullPointerException if either 
                                //a or b are set to a null value by the
                                //calling method
    successfulAdditionAlert(c);
    return c;
}

private void successfulAdditionAlert(Integer c) {
    try {
        //Code here to read configurations and send email alerts.
    } catch (Throwable e) {
        //Code to log any exception that occurs during email dispatch
    }
}

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


मैं कोशिश करूंगा और ईमेल भेजने के काम के लिए एक धागा (एक कतार के साथ) समर्पित करके इससे बचूं।
बुचंभ

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