जाँच अपवाद के खिलाफ मामला


456

कई वर्षों से अब मैं निम्नलिखित प्रश्न का माकूल जवाब नहीं दे पा रहा हूं: कुछ डेवलपर्स चेक किए गए अपवादों के खिलाफ क्यों हैं? मेरी कई बातचीत हुई हैं, ब्लॉग पर चीजें पढ़ीं, ब्रूस एकेल को क्या कहना है (मैंने पहले व्यक्ति को उनके बारे में बोलते देखा था) पढ़ें।

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

मेरी हर बातचीत उसी प्रश्न के साथ समाप्त होती है जो अनुत्तरित है ... मुझे इसे सेट करने दें:

सामान्य तौर पर (कैसे जावा डिजाइन किया गया था),

  • Error उन चीजों के लिए है जिन्हें कभी नहीं पकड़ा जाना चाहिए (वीएम में मूंगफली एलर्जी है और किसी ने मूंगफली का एक जार गिरा दिया)
  • RuntimeException उन चीजों के लिए है जो प्रोग्रामर ने गलत किया (प्रोग्रामर एक सरणी के अंत से चला गया)
  • Exception(को छोड़कर RuntimeException) प्रोग्रामर के नियंत्रण से बाहर की चीजों के लिए है (डिस्क फाइल सिस्टम पर लिखते समय भरता है, प्रक्रिया के लिए फ़ाइल हैंडल की सीमा पूरी हो चुकी है और आप कोई और फाइल नहीं खोल सकते हैं)
  • Throwable बस अपवाद प्रकार के सभी के माता पिता है।

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

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

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

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

मेरे पास रैपिंग के साथ कोई समस्या नहीं है catch(Exception)(या कुछ मामलों catch(Throwable)में यह सुनिश्चित करने के लिए कि कार्यक्रम इनायत से बाहर निकल सकता है - लेकिन मुझे हमेशा उन विशिष्ट अपवादों को पकड़ना होगा जिनकी मुझे आवश्यकता है। ऐसा करने से मुझे बहुत कम से कम, एक उपयुक्त प्रदर्शित होता है। त्रुटि संदेश।

सवाल यह है कि लोग कभी भी इसका जवाब नहीं देते हैं:

यदि आप RuntimeException उपवर्गों के बजाय उपवर्गों को फेंकते हैं Exception तो आप कैसे जानते हैं कि आपको क्या पकड़ना चाहिए?

यदि उत्तर पकड़ा जाता है, Exceptionतो आप प्रोग्रामर त्रुटियों से उसी तरह निपट रहे हैं जैसे सिस्टम अपवाद। जो मुझे गलत लगता है।

यदि आप पकड़ते हैं Throwableतो आप सिस्टम अपवादों और VM त्रुटियों (और इसी तरह) का इलाज कर रहे हैं। जो मुझे गलत लगता है।

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

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

इसलिए, यदि आपको चेक किए गए अपवाद पसंद नहीं हैं, तो आप बता सकते हैं कि क्यों नहीं और उस प्रश्न का उत्तर दें जिसका उत्तर कृपया नहीं देते हैं?

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


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

6
आ जाओ। भाषा की विशेषता के रूप में देखा गया, यह विषय रहा है और इसे वस्तुनिष्ठ तरीके से लिया जा सकता है।
कर्ट शेलफथआउट

6
@ क्लेटस "यदि आपके पास अपने सवाल का जवाब है" अगर मेरे पास जवाब होता तो मैं सवाल नहीं पूछता!
टोफूबीर

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

4
चेक किए गए अपवादों के लिए मुझे पता है कि सबसे मजबूत तर्क यह है कि वे मूल रूप से जावा में नहीं थे, और जब उन्हें पेश किया गया था तो उन्होंने जेडीके में सैकड़ों बग की खोज की थी। यह जावा 1.0 से कुछ पहले है। मैं व्यक्तिगत रूप से उनके बिना नहीं होगा, और इस पर ब्रूस एकेल और अन्य लोगों के साथ हिंसक रूप से असहमत थे।
लोर्ने

जवाबों:


276

मुझे लगता है कि मैंने वही ब्रूस एकेल इंटरव्यू पढ़ा था जो आपने किया था - और यह हमेशा मुझे बुरा लगा। वास्तव में, साक्षात्कारकर्ता द्वारा तर्क दिया गया था (यदि यह वास्तव में वह पद है जिसके बारे में आप बात कर रहे हैं) एंडर्स हेजलबर्ग, .NET और C # के पीछे एमएस जीनियस हैं।

http://www.artima.com/intv/handcuffs.html

फैन हालांकि मैं हेजलबर्ग और उनके काम का हूं, लेकिन इस तर्क ने मुझे हमेशा संगीन बना दिया है। यह मूल रूप से उबलता है:

"चेक किए गए अपवाद बुरे हैं क्योंकि प्रोग्रामर उन्हें हमेशा उन्हें पकड़ने और उन्हें खारिज करने का दुरुपयोग करते हैं जिससे समस्याओं को छिपाया जाता है और अनदेखा किया जाता है जो अन्यथा उपयोगकर्ता को प्रस्तुत किया जाएगा"।

द्वारा "अन्यथा उपयोगकर्ता के लिए प्रस्तुत" यदि आप एक क्रम अपवाद का उपयोग मेरा मतलब है आलसी प्रोग्रामर बस पर ध्यान नहीं देगा यह (एक खाली कैच ब्लॉक के साथ पकड़ने की तुलना में) और उपयोगकर्ता इसे देखेंगे।

तर्क के सारांश का सारांश यह है कि "प्रोग्रामर उन्हें ठीक से उपयोग नहीं करेंगे और उनका ठीक से उपयोग नहीं करना उनके नहीं होने से भी बदतर है"

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

लेकिन अंत में, मैं इसे हेजेल्सबर्ग का फर्जी तर्क मानता हूं और संभवतः एक पोस्ट-हॉक जो एक अच्छी तरह से सोचा गया निर्णय के बजाय कमी को समझाने के लिए बनाया गया है।

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

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

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

C में मुहावरा कुछ इस तरह से चलता है

  if (f = fopen("goodluckfindingthisfile")) { ... } 
  else { // file not found ...

जहाँ fopen0 और C को वापस करने में विफलता इंगित करती है (मूर्खतापूर्ण) आप 0 को एक बूलियन के रूप में मानते हैं और ... मूल रूप से, आप इस मुहावरे को सीखते हैं और आप ठीक हैं। लेकिन क्या हो अगर आप एक नॉब हैं और आपने मुहावरा नहीं सीखा है। फिर, बेशक, आप के साथ शुरू करते हैं

   f = fopen("goodluckfindingthisfile");
   f.read(); // BANG! 

और कठिन तरीका सीखें।

ध्यान दें कि हम यहां केवल दृढ़ता से टाइप की गई भाषाओं के बारे में बात कर रहे हैं: एक स्पष्ट रूप से टाइप की गई भाषा में एक एपीआई क्या है, इसका स्पष्ट विचार है: यह प्रत्येक के लिए एक स्पष्ट रूप से परिभाषित प्रोटोकॉल के साथ उपयोग करने के लिए आपके लिए कार्यक्षमता (विधियों) का एक smorgasbord है।

यह स्पष्ट रूप से परिभाषित प्रोटोकॉल आमतौर पर एक विधि हस्ताक्षर द्वारा परिभाषित किया गया है। यहां फ़ोपेन की आवश्यकता है कि आप इसे एक स्ट्रिंग (या सी के मामले में एक चार *) पास करें। यदि आप इसे कुछ और देते हैं तो आपको एक संकलन-समय त्रुटि मिलती है। आपने प्रोटोकॉल का पालन नहीं किया - आप ठीक से एपीआई का उपयोग नहीं कर रहे हैं।

कुछ (अस्पष्ट) भाषाओं में रिटर्न प्रकार प्रोटोकॉल का भी हिस्सा है। यदि आप fopen()इसे चर के लिए असाइन किए बिना कुछ भाषाओं के समतुल्य कॉल करने का प्रयास करते हैं, तो आपको एक संकलन-समय त्रुटि भी मिलेगी (आप केवल शून्य कार्यों के साथ ऐसा कर सकते हैं)।

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

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

तो, जाँच किए गए अपवादों के बारे में क्या?

अच्छी तरह से यहाँ जावा एपीआई आप एक फ़ाइल खोलने के लिए उपयोग कर सकते हैं।

try {
  f = new FileInputStream("goodluckfindingthisfile");
}
catch (FileNotFoundException e) {
  // deal with it. No really, deal with it!
  ... // this is me dealing with it
}

देखिए वो कैच? यहाँ उस एपीआई विधि के लिए हस्ताक्षर हैं:

public FileInputStream(String name)
                throws FileNotFoundException

ध्यान दें कि FileNotFoundExceptionएक जाँच अपवाद है।

एपीआई प्रोग्रामर आपसे यह कह रहा है: "आप इस निर्माता का उपयोग एक नया FileInputStream बनाने के लिए कर सकते हैं लेकिन आप

a) स्ट्रिंग नाम के रूप में फ़ाइल नाम में पास होना चाहिए
) इस संभावना को स्वीकार करना चाहिए कि फ़ाइल रनटाइम पर नहीं मिल सकती है "

और यह पूरा बिंदु है जहाँ तक मेरा सवाल है।

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

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

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

यह एक काउंटर-केस के साथ स्पष्ट होगा। कल्पना कीजिए कि मैं एक टेबल एपीआई लिख रहा हूं। मेरे पास इस पद्धति सहित एपीआई के साथ टेबल मॉडल कहीं है:

public RowData getRowData(int row) 

अब मैं एक एपीआई प्रोग्रामर के रूप में जानता हूं कि ऐसे मामले होंगे जहां कुछ क्लाइंट पंक्ति के लिए एक नकारात्मक मूल्य या तालिका के बाहर एक पंक्ति मूल्य से गुजरता है। इसलिए मुझे एक अपवाद को फेंकने के लिए लुभाया जा सकता है और ग्राहक को इससे निपटने के लिए मजबूर कर सकता है:

public RowData getRowData(int row) throws CheckedInvalidRowNumberException

(मैं वास्तव में इसे "जाँच" निश्चित रूप से नहीं कहूंगा।)

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

एपीआई प्रोग्रामर अभी भी भविष्यवाणी कर सकता है कि ग्राहक ऐसे बगों को कोड करेगा और इसे एक रनटाइम अपवाद जैसे ए के साथ संभालना चाहिए IllegalArgumentException

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

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

मुझे लगता है कि यह एक सटीक विज्ञान नहीं है और मुझे लगता है कि अंडरलाइज़ और शायद एक हद तक हेज्सबर्ग के तर्क को सही ठहराता है। लेकिन मैं खुश नहीं हूँ कि बच्चे को यहाँ नहाने के पानी के साथ फेंक दिया जाए, इसलिए मुझे यहाँ से कुछ अच्छे नियमों को अलग करने के लिए कुछ नियम निकालने की अनुमति दें:

  1. ग्राहक के नियंत्रण से बाहर या बंद बनाम खुला:

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

  2. सर्वव्यापकता:

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

    if (model.getRowData().getCell(0).isEmpty())

    और हर बार कोशिश / पकड़ में लपेटना दर्दनाक होगा।

  3. उपयोगकर्ता को सूचित करना:

    चेक किए गए अपवादों का उपयोग उन मामलों में किया जाना चाहिए जहां आप अंतिम उपयोगकर्ता के लिए प्रस्तुत किए जा रहे एक उपयोगी त्रुटि संदेश की कल्पना कर सकते हैं। यह "और क्या होगा जब आप ऐसा करेंगे?" सवाल मैंने ऊपर उठाया। यह आइटम 1 से भी संबंधित है। जब से आप यह अनुमान लगा सकते हैं कि आपके क्लाइंट-एपीआई सिस्टम के बाहर की कोई चीज फाइल नहीं हो सकती है, तो आप उपयोगकर्ता को इसके बारे में उचित रूप से बता सकते हैं:

    "Error: could not find the file 'goodluckfindingthisfile'"

    चूँकि आपका अवैध रो नंबर आंतरिक बग के कारण और उपयोगकर्ता की कोई गलती के कारण नहीं था, इसलिए वास्तव में कोई उपयोगी जानकारी नहीं है जो आप उन्हें दे सकते हैं। यदि आपका ऐप रनटाइम अपवादों को कंसोल के माध्यम से गिरने नहीं देता है, तो संभवतः यह उन्हें कुछ बदसूरत संदेश दे रहा है जैसे:

    "Internal error occured: IllegalArgumentException in ...."

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

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

क्षमा करें, इसका मतलब यह नहीं है कि यह इतनी लंबी और भयावह है। मुझे दो सुझावों के साथ समाप्त करने दें:

ए: एपीआई प्रोग्रामर: उनकी उपयोगिता को संरक्षित करने के लिए जाँच किए गए अपवादों का उपयोग करें। जब संदेह में एक अनियंत्रित अपवाद का उपयोग करें।

बी: ग्राहक प्रोग्रामर: अपने विकास में जल्दी से एक लिपटे अपवाद (इसे गूगल करें) बनाने की आदत डालें। JDK 1.4 और बाद में इसके लिए एक कंस्ट्रक्टर प्रदान RuntimeExceptionकरें, लेकिन आप आसानी से अपना खुद का भी निर्माण कर सकते हैं। यहाँ निर्माता है:

public RuntimeException(Throwable cause)

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

try {
  overzealousAPI(thisArgumentWontWork);
}
catch (OverzealousCheckedException exception) {
  throw new RuntimeException(exception);  
}

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

catch (Exception e) { /* TODO deal with this at some point (yeah right) */}

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

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

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

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

7
गलत @Rhubarb। जाँच किए गए अपवाद 'आकस्मिकताओं' के लिए अभिप्रेत थे, जिन्हें नियंत्रित किया जा सकता था, लेकिन हमेशा "जल्दी फेंकना, देर से पकड़ना" सर्वोत्तम अभ्यास के साथ असंगत थे। एक फ़ाइल खोलना एक चेरी-उठाया उदाहरण है, जिसे संभाला जा सकता है। अधिकांश IOException (जैसे एक बाइट लिखना), SQLException, RemoteException को अर्थपूर्ण तरीके से संभालना असंभव है। असफलता या पुन: प्रयास "व्यवसाय" या "अनुरोध" स्तर पर होना चाहिए, और जाँच किए गए अपवाद - जैसा कि जावा पुस्तकालयों में उपयोग किया जाता है - एक ऐसी गलती है जो कि मुश्किल बनाती है। literatejava.com/exception/…
थॉमस डब्ल्यू

184

जाँच किए गए अपवादों के बारे में बात यह है कि वे अवधारणा की सामान्य समझ से वास्तव में अपवाद नहीं हैं। इसके बजाय, वे एपीआई वैकल्पिक रिटर्न मान हैं।

अपवादों का पूरा विचार यह है कि कॉल चेन के नीचे किसी तरह से एक एरर फेंकी जा सकती है और कोड द्वारा नियंत्रित किया जा सकता है, और इसके बिना इंटरव्यू कोड के बारे में चिंता किए बिना। दूसरी ओर, अपवादों की जांच की जाती है, उन्हें फेंकने वाले और पकड़ने वाले के बीच हर स्तर के कोड की आवश्यकता होती है, यह घोषित करने के लिए कि वे अपवाद के सभी रूपों के बारे में जानते हैं जो उनके माध्यम से जा सकते हैं। यह वास्तव में अभ्यास में थोड़ा अलग है अगर जाँच किए गए अपवाद केवल विशेष रिटर्न मान थे जो कॉलर को जांचना था। जैसे [स्यूडोकोड]।:

public [int or IOException] writeToStream(OutputStream stream) {
    [void or IOException] a= stream.write(mybytes);
    if (a instanceof IOException)
        return a;
    return mybytes.length;
}

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

समस्या यह है कि मानक पुस्तकालय के महान स्वैट्स सहित बहुत सारे कोड, वास्तविक असाधारण परिस्थितियों के लिए जाँच किए गए अपवादों का दुरुपयोग करते हैं जिन्हें आप बहुत अच्छी तरह से कई स्तरों को पकड़ना चाहते हैं। IOException RuntimeException क्यों नहीं है? हर दूसरी भाषा में मैं एक IO अपवाद को होने दे सकता हूं, और अगर मैं इसे संभालने के लिए कुछ नहीं करता हूं, तो मेरा आवेदन बंद हो जाएगा और मुझे देखने के लिए एक आसान स्टैक ट्रेस मिलेगा। यह सबसे अच्छी चीज है जो हो सकती है।

हो सकता है कि दो विधियाँ उदाहरण से आप पूरी लेखन-प्रक्रिया से सभी IOException को पकड़ना चाहें, प्रक्रिया को निरस्त करें और त्रुटि रिपोर्टिंग कोड में कूदें; जावा में आप हर कॉल स्तर पर 'थ्रो IOException' को जोड़ने के बिना ऐसा नहीं कर सकते, यहां तक ​​कि स्तर जो खुद को कोई IO नहीं करते हैं। अपवाद हैंडलिंग के बारे में इस तरह के तरीकों को जानने की आवश्यकता नहीं होनी चाहिए; उनके हस्ताक्षरों में अपवादों को जोड़ना:

  1. अनावश्यक रूप से युग्मन बढ़ाता है;
  2. इंटरफ़ेस हस्ताक्षर को बदलने के लिए बहुत भंगुर बनाता है;
  3. कोड को कम पठनीय बनाता है;
  4. यह इतना कष्टप्रद है कि यह सामान्य प्रोग्रामर प्रतिक्रिया है कि 'थ्रोस एक्सेप्शन', 'कैच (अपवाद ई) {}' जैसे कुछ भयानक करके सिस्टम को हराना है, या एक रनटाइम एक्ससेप्शन (जो डीबगिंग को कठिन बनाता है) में सब कुछ लपेट देता है।

और फिर बहुत हास्यास्पद पुस्तकालय अपवाद हैं जैसे:

try {
    httpconn.setRequestMethod("POST");
} catch (ProtocolException e) {
    throw new CanNeverHappenException("oh dear!");
}

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

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

जावा और इसके मानक पुस्तकालय में लागू किए गए अपवादों की जाँच की गई है मतलब बॉयलरप्लेट, बॉयलरप्लेट, बॉयलरप्लेट। पहले से ही मौखिक भाषा में यह जीत नहीं है।


14
आपके कोड उदाहरण में, अपवादों को श्रृंखलाबद्ध करना सबसे अच्छा होगा ताकि लॉग पढ़ते समय मूल कारण मिल सके: CanNeverHappenException (e) फेंकें;
एस्को लुओंटोला

5
मैं असहमत हूं। अपवाद, जाँच या नहीं, असाधारण स्थितियाँ हैं। उदाहरण: एक विधि जो HTTP के माध्यम से किसी वस्तु को प्राप्त करती है। वापसी मूल्य वस्तु या कुछ भी नहीं है, सभी चीजें जो खराब हो सकती हैं वे असाधारण हैं। उन्हें सी मान के रूप में वापसी मान के रूप में यह केवल भ्रम और खराब डिजाइन की ओर जाता है।
मिस्टर स्मिथ

15
@ मिस्टर: मैं जो कह रहा हूं, वह यह है कि जावा में कार्यान्वित किए गए अपवादों को चेक किया जाता है, व्यवहार में, सी में रिटर्न मानों की तुलना में अधिक के रूप में वे पारंपरिक 'अपवादों' को करते हैं जिन्हें हम C ++ और अन्य प्री-जावा भाषाओं से पहचान सकते हैं। और यह IMO वास्तव में भ्रम और खराब डिजाइन की ओर ले जाता है।
bobince

9
इस बात से सहमत हैं कि जाँच किए गए अपवादों के मानक पुस्तकालयों का दुरुपयोग निश्चित रूप से भ्रम और बुरे पकड़ने वाले व्यवहार में जोड़ा गया है। और, अक्सर यह सिर्फ खराब प्रलेखन से होता है, उदाहरण के लिए डिस्कनेक्ट () की तरह एक आंसू नीचे की विधि जो IOException को फेंकता है जब "कुछ अन्य I / O त्रुटि होती है"। खैर, मैं डिस्कनेक्ट कर रहा था! क्या मैं एक हैंडल या अन्य संसाधन लीक कर रहा हूं? क्या मुझे पुनः प्रयास करने की आवश्यकता है? यह जानने के बिना कि ऐसा क्यों हुआ, मुझे जो कार्रवाई करनी चाहिए वह मैं नहीं कर सकता और इसलिए मुझे यह अनुमान लगाना होगा कि क्या मुझे इसे निगल लेना चाहिए, फिर से प्रयास करना चाहिए या जमानत देनी चाहिए।
charstar

14
"एपीआई वैकल्पिक वापसी मूल्यों" के लिए +1। जाँच किए गए अपवादों को देखने का दिलचस्प तरीका।
Zsolt Török

75

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

try {
  // do stuff
} catch (AnnoyingcheckedException e) {
  throw new RuntimeException(e);
}

99% समय मैं इसके बारे में कुछ नहीं कर सकता। अंत में ब्लॉक किसी भी आवश्यक सफाई (या कम से कम उन्हें करना चाहिए) करते हैं।

मैंने यह देखा है कि मैंने कितनी बार गिनती की है:

try {
  // do stuff
} catch (AnnoyingCheckedException e) {
  // do nothing
}

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

और फिर हमारे पास infuriating कोड है जो अपवादों का उपयोग फ्लो कंट्रोल के रूप में करता है, जैसे java.text ।ormat करता है। Bzzzt। गलत। प्रपत्र पर संख्या फ़ील्ड में "abc" डालने वाला उपयोगकर्ता अपवाद नहीं है।

ठीक है, मुझे लगता है कि तीन कारण थे।


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

3
ध्यान दें कि try-catch-rethrow आपको एक संदेश निर्दिष्ट करने की अनुमति देता है - मैं आमतौर पर इसका उपयोग राज्य चर की सामग्री के बारे में जानकारी जोड़ने के लिए करता हूं। एक लगातार उदाहरण IOException के लिए प्रश्न में फ़ाइल के निरपेक्ष नाम () को जोड़ने के लिए है।
थोर्बोजर्न रेवन एंडरसन

15
मुझे लगता है कि ग्रहण जैसे आईडीई के पास खाली पकड़ने वाले ब्लॉक को देखने के लिए कई बार दोष है। वास्तव में, उन्हें डिफ़ॉल्ट रूप से पुनर्विचार करना चाहिए।
आर्टब्रिस्टल

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

2
@YasmaniLlanes आप हमेशा इन चीजों को नहीं कर सकते। कभी-कभी आपका पालन करने के लिए एक इंटरफ़ेस होता है। और यह विशेष रूप से सच है जब आप अच्छे रख-रखाव वाले एपीआई डिज़ाइन करते हैं क्योंकि आप केवल सभी जगहों पर साइड-इफेक्ट्स फेंकना शुरू नहीं कर सकते हैं। दोनों, और यह जिस जटिलता को पेश करेगा, वह आपको बड़े पैमाने पर गंभीर रूप से काटेगा। तो हाँ, समय का 99%, इसके बारे में कुछ भी नहीं किया जाना है।
मास्टरमैटिक

50

मुझे पता है कि यह एक पुराना प्रश्न है, लेकिन मैंने कुछ समय कुश्ती के लिए जाँच की अपवादों के साथ बिताया है और मुझे कुछ जोड़ना है। कृपया मुझे इसकी लंबाई के लिए क्षमा करें!

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

अच्छा ol 'Java Listइंटरफ़ेस लें। हमारे पास आम-इन-मेमोरी कार्यान्वयन जैसे ArrayListऔर हैं LinkedList। हमारे पास कंकाल वर्ग भी है AbstractListजो नए प्रकार की सूची तैयार करना आसान बनाता है। केवल-पढ़ने के लिए सूची के लिए हमें केवल दो विधियों को लागू करने की आवश्यकता है: size()और get(int index)

यह उदाहरण WidgetListवर्ग Widgetएक फ़ाइल से कुछ निश्चित आकार की वस्तुओं (नहीं दिखाया गया) को पढ़ता है :

class WidgetList extends AbstractList<Widget> {
    private static final int SIZE_OF_WIDGET = 100;
    private final RandomAccessFile file;

    public WidgetList(RandomAccessFile file) {
        this.file = file;
    }

    @Override
    public int size() {
        return (int)(file.length() / SIZE_OF_WIDGET);
    }

    @Override
    public Widget get(int index) {
        file.seek((long)index * SIZE_OF_WIDGET);
        byte[] data = new byte[SIZE_OF_WIDGET];
        file.read(data);
        return new Widget(data);
    }
}

परिचित Listइंटरफ़ेस का उपयोग करके विजेट्स को उजागर करके , आप अपने बारे में जानने की आवश्यकता के बिना आइटम पुनर्प्राप्त कर सकते हैं ( list.get(123)) या एक सूची ( for (Widget w : list) ...) को पुन: व्यवस्थित कर सकते हैं WidgetList। कोई भी इस सूची को किसी भी मानक तरीके से पारित कर सकता है जो जेनेरिक सूचियों का उपयोग करता है, या इसे एक में लपेटता है Collections.synchronizedList। कोड जो इसका उपयोग करता है उसे न तो यह जानने की जरूरत है और न ही परवाह है कि "विजेट" मौके पर बने हैं, एक सरणी से आते हैं, या एक फ़ाइल, या डेटाबेस, या पूरे नेटवर्क से या भविष्य के उप-रिले रिले से पढ़े जाते हैं। यह अभी भी सही ढंग से काम करेगा क्योंकि Listइंटरफ़ेस सही ढंग से लागू किया गया है।

सिवाय इसके कि नहीं है। उपरोक्त वर्ग संकलित नहीं करता है क्योंकि फ़ाइल एक्सेस विधियाँ एक IOException, एक अपवादित अपवाद को फेंक सकती हैं , जिसे आपको "पकड़ना या निर्दिष्ट करना" है। आप इसे फेंकने के रूप में निर्दिष्ट नहीं कर सकते - संकलक आपको नहीं देगा क्योंकि यह Listइंटरफ़ेस के अनुबंध का उल्लंघन करेगा । और कोई उपयोगी तरीका नहीं है जो WidgetListस्वयं अपवाद को संभाल सकता है (जैसा कि मैं बाद में उजागर करूँगा)।

जाहिरा तौर पर केवल एक चीज को पकड़ना और कुछ अनियंत्रित अपवाद के रूप में अपवादों की जाँच करना है:

@Override
public int size() {
    try {
        return (int)(file.length() / SIZE_OF_WIDGET);
    } catch (IOException e) {
        throw new WidgetListException(e);
    }
}

public static class WidgetListException extends RuntimeException {
    public WidgetListException(Throwable cause) {
        super(cause);
    }
}

((संपादित करें: जावा 8 ने UncheckedIOExceptionइस मामले के लिए एक वर्ग जोड़ा है : IOExceptionपॉलीमॉर्फिक पद्धति की सीमाओं के पार s को पकड़ने और पुनर्विचार करने के लिए। मेरी बात साबित करने के लिए!)।

इसलिए अपवादों की जाँच इस तरह के मामलों में नहीं होती है । आप उन्हें फेंक नहीं सकते। Mapएक डेटाबेस द्वारा समर्थित एक चतुर , या java.util.Randomएक COM पोर्ट के माध्यम से एक क्वांटम एन्ट्रापी स्रोत से जुड़े के कार्यान्वयन के लिए डिट्टो। जैसे ही आप एक पॉलिमॉर्फिक इंटरफ़ेस के कार्यान्वयन के साथ कुछ भी करने की कोशिश करते हैं, चेक किए गए अपवादों की अवधारणा विफल हो जाती है। लेकिन जाँच किए गए अपवाद इतने कपटी हैं कि वे अभी भी आपको शांति से नहीं छोड़ेंगे, क्योंकि आपको अभी भी निचले-स्तर के तरीकों में से किसी को पकड़ना और हटाना है, कोड को अव्यवस्थित करना और स्टैक ट्रेस को अव्यवस्थित करना है।

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

वास्तव में, यदि आप हैक का सहारा लेते हैं, तो आप अघोषित जाँच अपवादों को फेंक सकते हैं । JVM, रन टाइम में, चेक किए गए अपवाद नियमों की परवाह नहीं करता है, इसलिए हमें केवल कंपाइलर को मूर्ख बनाने की आवश्यकता है। ऐसा करने का सबसे आसान तरीका है जेनरिक का दुरुपयोग करना। यह इसके लिए मेरी विधि है (वर्ग नाम दिखाया गया है क्योंकि (जावा 8 से पहले) यह जेनेरिक विधि के लिए कॉलिंग सिंटैक्स में आवश्यक है:

class Util {
    /**
     * Throws any {@link Throwable} without needing to declare it in the
     * method's {@code throws} clause.
     * 
     * <p>When calling, it is suggested to prepend this method by the
     * {@code throw} keyword. This tells the compiler about the control flow,
     * about reachable and unreachable code. (For example, you don't need to
     * specify a method return value when throwing an exception.) To support
     * this, this method has a return type of {@link RuntimeException},
     * although it never returns anything.
     * 
     * @param t the {@code Throwable} to throw
     * @return nothing; this method never returns normally
     * @throws Throwable that was provided to the method
     * @throws NullPointerException if {@code t} is {@code null}
     */
    public static RuntimeException sneakyThrow(Throwable t) {
        return Util.<RuntimeException>sneakyThrow1(t);
    }

    @SuppressWarnings("unchecked")
    private static <T extends Throwable> RuntimeException sneakyThrow1(
            Throwable t) throws T {
        throw (T)t;
    }
}

हुर्रे! इसका उपयोग करके हम किसी भी गहराई से चेक किए गए अपवाद को बिना घोषित किए बिना स्टैक के ऊपर फेंक सकते हैं, इसे बिना लपेटे RuntimeExceptionऔर स्टैक ट्रेस को हटाए बिना! फिर से "WidgetList" उदाहरण का उपयोग करना:

@Override
public int size() {
    try {
        return (int)(file.length() / SIZE_OF_WIDGET);
    } catch (IOException e) {
        throw sneakyThrow(e);
    }
}

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

try {
    ...
} catch (Throwable t) { // catch everything
    if (t instanceof IOException) {
        // handle it
        ...
    } else {
        // didn't want to catch this one; let it go
        throw t;
    }
}

यह थोड़ा अजीब है, लेकिन प्लस साइड पर, यह अभी भी एक चेक अपवाद को निकालने के लिए कोड की तुलना में थोड़ा सरल है जो एक में लपेटा गया था RuntimeException

खुशी से, throw t;बयान यहां कानूनी है, भले ही प्रकार की tजाँच की जाती है, पकड़े गए आयनों को पुनर्विचार करने के बारे में जावा 7 में जोड़े गए एक नियम के लिए धन्यवाद।


जब जांच किए गए अपवाद बहुरूपता से मिलते हैं, तो विपरीत स्थिति भी एक समस्या है: जब एक विधि एक निर्दिष्ट अपवाद को फेंकने के रूप में कल्पना होती है, लेकिन एक ओवरराइड कार्यान्वयन नहीं होता है। उदाहरण के लिए, अमूर्त वर्ग OutputStreamके writeतरीके सभी निर्दिष्ट करते हैं throws IOExceptionByteArrayOutputStreamएक उपवर्ग है जो एक सच्चे I / O स्रोत के बजाय इन-मेमोरी सरणी में लिखता है। इसके अतिरंजित writeतरीकों का कारण नहीं बन सकताIOException एस का , इसलिए उनके पास कोई throwsक्लॉज नहीं है, और आप कैच-या-निर्दिष्ट आवश्यकता के बारे में चिंता किए बिना उन्हें कॉल कर सकते हैं।

सिवाय हमेशा नहीं। मान लीजिए कि Widgetएक धारा के लिए इसे बचाने के लिए एक विधि है:

public void writeTo(OutputStream out) throws IOException;

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

ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
    someWidget.writeTo(out);
} catch (IOException e) {
    // can't happen (although we shouldn't ignore it if it does)
    throw new RuntimeException(e);
}

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

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

यह नियम कुछ बेतुकी समस्याओं का कारण बनता है। उदाहरण के लिए, इन तीन writeतरीकों में से OutputStreamएक को ओवरराइड नहीं किया जाता है ByteArrayOutputStream। विशेष रूप से, write(byte[] data)एक सुविधा विधि है जो write(byte[] data, int offset, int length)0 की ऑफसेट और सरणी की लंबाई के साथ कॉल करके पूर्ण सरणी लिखती है । ByteArrayOutputStreamतीन-तर्क पद्धति को ओवरराइड करता है लेकिन एक-तर्क सुविधा विधि को विरासत में मिला है। विरासत में मिली विधि बिल्कुल सही काम करती है, लेकिन इसमें एक अवांछित throwsखंड शामिल है। यह शायद के डिजाइन में एक निरीक्षण थाByteArrayOutputStream , लेकिन वे इसे कभी भी ठीक नहीं कर सकते क्योंकि यह किसी भी कोड के साथ स्रोत संगतता को तोड़ देगा जो अपवाद को पकड़ता है - अपवाद जो कभी नहीं था, कभी नहीं है, और कभी भी फेंका नहीं जाएगा!

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


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

इसके बजाय, हमें निम्नलिखित मुहावरे मिलते हैं, जो कंपाइलर को बंद करने के तरीके के रूप में व्याप्त हैं:

try {
    ...
} catch (SomeStupidExceptionOmgWhoCares e) {
    e.printStackTrace();
}

GUI या स्वचालित प्रोग्राम में मुद्रित संदेश नहीं देखा जाएगा। इससे भी बदतर, यह अपवाद के बाद बाकी कोड के साथ जुताई करता है। क्या अपवाद वास्तव में त्रुटि नहीं है? फिर इसे मत छापना। अन्यथा, एक पल में कुछ और उड़ने वाला है, जिस समय तक मूल अपवाद वस्तु चली जाएगी। यह मुहावरा BASIC On Error Resume Nextor PHP's से बेहतर नहीं है error_reporting(0);

कुछ प्रकार के लकड़हारे वर्ग को कॉल करना बेहतर नहीं है:

try {
    ...
} catch (SomethingWeird e) {
    logger.log(e);
}

यह बस के रूप में के रूप में आलसी है e.printStackTrace();और अभी भी एक अनिश्चित स्थिति में कोड के साथ प्रतिज्ञा करता है। इसके अलावा, एक विशेष लॉगिंग सिस्टम या अन्य हैंडलर की पसंद एप्लिकेशन-विशिष्ट है, इसलिए यह कोड का पुन: उपयोग करता है।

लेकिन रुकें! एप्लिकेशन-विशिष्ट हैंडलर को खोजने का एक आसान और सार्वभौमिक तरीका है। यह कॉल स्टैक ऊपर है (या यह थ्रेड के अनकैप्ड अपवाद हैंडलर के रूप में सेट है )। तो ज्यादातर जगहों पर, आपको केवल इतना करना होगा कि आप स्टैक को ऊंचा छोड़ दें । जैसे throw e;,। चेक किए गए अपवाद केवल रास्ते में मिलते हैं।

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


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

2
SomeStupidExceptionOmgWhoCares किसी ने इसे फेंकने के लिए पर्याप्त देखभाल की। तो या तो इसे कभी भी खराब नहीं होना चाहिए (खराब डिजाइन) या आपको वास्तव में इसे संभालना चाहिए। वही पूर्व-1.0 वर्ग (बाइट एरे आउटपुट स्ट्रीम) के खराब कार्यान्वयन के बारे में सच है, जहां डिजाइन दुर्भाग्य से खराब था।
टोफूबीर

2
उचित मुहावरा एक निर्देश होता जो नेस्टेड सबरूटीन कॉल द्वारा फेंके गए किसी भी निर्दिष्ट अपवाद को पकड़ता और उनमें लिपटे हुए को फिर से फेंक देता RuntimeException। ध्यान दें कि एक दिनचर्या को एक साथ घोषित किया जा सकता है throws IOExceptionऔर फिर भी यह निर्दिष्ट IOExceptionकरना चाहिए कि किसी नेस्टेड कॉल से फेंकी गई किसी भी चीज को अप्रत्याशित और लपेटा हुआ माना जाना चाहिए।
सुपरैट

15
मैं कुछ जावा अनुभव के साथ एक पेशेवर सी # डेवलपर हूं जो इस पद पर ठोकर खाई। मैं इस बात से हैरान हूं कि कोई भी इस विचित्र व्यवहार का समर्थन क्यों करेगा। .NET में अगर मैं एक विशेष प्रकार के अपवाद को पकड़ना चाहता हूं, तो मैं उसे पकड़ सकता हूं। अगर मैं बस स्टैक को फेंकने देना चाहता हूं, तो कुछ भी नहीं करना है। काश जावा इतना विचित्र नहीं था। :)
अनिकेरु

के बारे में "कभी-कभी मैं अस्थायी रूप से एक विधि कॉल पर टिप्पणी करूंगा" - मैंने इसके लिए उपयोग करना सीखा if (false)। यह थ्रो क्लॉज की समस्या से बचा जाता है और चेतावनी मुझे तेजी से वापस नेविगेट करने में मदद करती है। +++ ने कहा, मैं आपके द्वारा लिखी गई हर बात से सहमत हूं। चेक किए गए अपवादों का कुछ मूल्य है, लेकिन उनकी कीमत की तुलना में यह मूल्य नगण्य है। लगभग हमेशा वे रास्ते में ही मिलते हैं।
माॅर्टिनस

45

खैर, यह स्टैकट्रेस प्रदर्शित करने या चुपचाप दुर्घटनाग्रस्त होने के बारे में नहीं है। यह परतों के बीच त्रुटियों को संवाद करने में सक्षम होने के बारे में है।

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

मैं वास्तव में इस स्थिति से अब एक आवेदन में निपट रहा हूं। हमने लगभग अपवादों को AppSpecificException के रूप में निरस्त कर दिया। इससे हस्ताक्षर वास्तव में साफ हो गए और हमें throwsहस्ताक्षरों में विस्फोट की चिंता नहीं करनी पड़ी ।

बेशक, अब हमें उच्च स्तर पर त्रुटि से निपटने में विशेषज्ञ होने की आवश्यकता है, जो रिट्री लॉजिक और इस तरह लागू हो। सब कुछ AppSpecificException है, हालांकि, इसलिए हम यह नहीं कह सकते हैं "यदि एक IOException फेंक दिया जाता है, तो फिर से प्रयास करें" या "अगर ClassNotFound फेंक दिया गया है, तो पूरी तरह से गर्भपात करें"। हमारे पास वास्तविक अपवाद को प्राप्त करने का एक विश्वसनीय तरीका नहीं है क्योंकि चीजें फिर से दोबारा प्राप्त होती हैं और जैसे ही वे हमारे कोड और तीसरे पक्ष के कोड के बीच से गुजरते हैं।

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

मैंने पाया है, समय और फिर से, और पूरे प्रोजेक्ट में मैंने उल्लेख किया, कि अपवाद हैंडलिंग 3 श्रेणियों में आती है:

  1. विशिष्ट अपवाद को पकड़ें और संभालें । उदाहरण के लिए, रिट्री लॉजिक को लागू करना है।
  2. अन्य अपवादों को पकड़ें और फिर से उखाड़ें । यहां जो कुछ भी होता है वह आमतौर पर लॉगिंग होता है, और आमतौर पर "$ फ़ाइल खोलने में असमर्थ" जैसे एक ट्रिट संदेश। ये ऐसी त्रुटियां हैं जिनके बारे में आप कुछ नहीं कर सकते; केवल एक उच्च स्तर इसे संभालने के लिए पर्याप्त जानता है।
  3. सब कुछ पकड़ो और एक त्रुटि संदेश प्रदर्शित करें। यह आम तौर पर एक डिस्पैचर की बहुत जड़ पर होता है, और यह सब यह सुनिश्चित करता है कि यह गैर-अपवाद तंत्र (पॉपअप संवाद, आरपीसी त्रुटि ऑब्जेक्ट आदि को मार्शलिंग) के माध्यम से कॉलर को त्रुटि का संचार कर सकता है।

5
आप सादे विधि हस्ताक्षर करते समय अलगाव की अनुमति देने के लिए AppSpecificException के विशिष्ट उपवर्ग बना सकते थे।
थोरबजोरन रेव एंडरसन

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

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

4
मैं जो कुछ भी कह रहा हूं, वह नहीं। आपका अंतिम वाक्य वास्तव में मेरे साथ सहमत है। यदि सब कुछ AppSpecificException में लिपटे हुए है, तो यह बबल नहीं करता है (और अर्थ / संदर्भ खो गया है), और, हां, API क्लाइंट को सूचित नहीं किया जा रहा है - यह वास्तव में चेक किए गए अपवादों के साथ होता है (जैसा कि वे जावा में हैं) , क्योंकि लोग बहुत सारी throwsघोषणाओं के साथ कार्यों से निपटना नहीं चाहते हैं ।
रिचर्ड लेवासेउर

6
@ न्यूटोपियन - अपवादों को केवल "व्यवसाय" या "अनुरोध" स्तर पर ही नियंत्रित किया जा सकता है। यह बड़ी ग्रैन्युलैरिटी को विफल करने या फिर से प्रयास करने के लिए समझ में आता है, हर छोटे संभावित विफलता के लिए नहीं। इस कारण से, अपवाद-हैंडलिंग सर्वोत्तम अभ्यास को "जल्दी फेंक, देर से पकड़ना" के रूप में संक्षेपित किया गया है। चेक किए गए अपवादों को सही स्तर पर विश्वसनीयता का प्रबंधन करना कठिन है, और बड़ी संख्या में गलत-कोडित कैच ब्लॉकों को प्रोत्साहित करना है। literatejava.com/exception/…
थॉमस डब्ल्यू

24

SNR

सबसे पहले, चेक किए गए अपवाद कोड के लिए "सिग्नल-टू-शोर अनुपात" को कम करते हैं। एंडर्स हेजलबर्ग भी अनिवार्य बनाम घोषित प्रोग्रामिंग के बारे में बात करते हैं जो एक समान अवधारणा है। वैसे भी निम्नलिखित कोड स्निपेट पर विचार करें:

जावा में गैर-यूआई-थ्रेड से यूआई अपडेट करें:

try {  
    // Run the update code on the Swing thread  
    SwingUtilities.invokeAndWait(() -> {  
        try {
            // Update UI value from the file system data  
            FileUtility f = new FileUtility();  
            uiComponent.setValue(f.readSomething());
        } catch (IOException e) {  
            throw new UncheckedIOException(e);
        }
    });
} catch (InterruptedException ex) {  
    throw new IllegalStateException("Interrupted updating UI", ex);  
} catch (InvocationTargetException ex) {
    throw new IllegalStateException("Invocation target exception updating UI", ex);
}

C # में नॉन UI-थ्रेड से UI अपडेट करें:

private void UpdateValue()  
{  
   // Ensure the update happens on the UI thread  
   if (InvokeRequired)  
   {  
       Invoke(new MethodInvoker(UpdateValue));  
   }  
   else  
   {  
       // Update UI value from the file system data  
       FileUtility f = new FileUtility();  
       uiComponent.Value = f.ReadSomething();  
   }  
}  

जो मुझे बहुत साफ लगता है। जब आप स्विंग चेक किए गए अपवादों में अधिक से अधिक यूआई काम करना शुरू करते हैं तो वास्तव में कष्टप्रद और बेकार होने लगते हैं।

जेल तोड़ो

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

@Override
public void clear()  
{  
   try  
   {  
       backingImplementation.clear();  
   }  
   catch (CheckedBackingImplException ex)  
   {  
       throw new IllegalStateException("Error clearing underlying list.", ex);  
   }  
}  

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

निष्कर्ष

  • अपवादों को पकड़ना उन्हें संभालने के लिए अलग है।
  • चेक किए गए अपवाद कोड में शोर जोड़ते हैं।
  • अपवाद हैंडलिंग उनके बिना C # में अच्छी तरह से काम करता है।

मैंने इसके बारे में पहले ब्लॉग किया था


3
उदाहरण में, Java और C # दोनों ही अपवादों को बिना हैंडल किए प्रचारित कर रहे हैं (Java with IllegalStateException)। अंतर यह है कि आप FileNotFoundException को संभालना चाहते हैं, लेकिन इसकी संभावना नहीं है कि InvocationTargetException या InterruptedException को हैंडल करना उपयोगी होगा।
ल्यूक क्विनेन

3
और C # तरीके से मुझे कैसे पता चलेगा कि I / O अपवाद हो सकता है? इसके अलावा, मैं कभी भी रन से अपवाद नहीं फेंकूंगा ... मैं मानता हूं कि अपवाद से निपटने के लिए दुर्व्यवहार करना। क्षमा करें, लेकिन आपके कोड के उस हिस्से के लिए मैं अभी इसके पक्ष को देख सकता हूं।
टोफूबीर

7
हम वहां पहुंच रहे हैं :-) इसलिए एपीआई के प्रत्येक नए रिलीज के साथ आपको अपने सभी कॉल्स के माध्यम से कंघी करना होगा और किसी भी नए अपवाद की तलाश करनी चाहिए जो हो सकता है? आसानी से एक कंपनी एपीआई के लिए आंतरिक के साथ हो सकता है क्योंकि उन्हें पीछे की संगतता के बारे में चिंता करने की ज़रूरत नहीं है।
टोफूबीर

3
क्या आपका मतलब था सिग्नल-टू-शोर अनुपात में कमी ?
neo2862

3
@TofuBeer एक अंडरलेइंग एपीआई के इंटरफेस के बाद अपने कोड को अपडेट करने के लिए मजबूर नहीं किया जा रहा है? यदि आपके पास केवल वहाँ अनियंत्रित अपवाद था, तो आप इसे जाने बिना टूटे / अपूर्ण कार्यक्रम के साथ समाप्त कर देंगे।
फ्रेंकोइस बुर्जुआ

23

अर्टिमा ने .NET, एंडर्स हेजेल्सबर्ग के आर्किटेक्ट में से एक के साथ एक साक्षात्कार प्रकाशित किया , जो चेक किए गए अपवादों के खिलाफ तर्कों को गंभीरता से शामिल करता है। एक छोटी ढलाईकार:

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


2
वास्तव में, मुख्य वास्तुकार।
ट्रैप

18
मैंने पढ़ा है कि, मेरे तर्क से "वहाँ खराब प्रोग्रामर हैं"।
टोफूबीर

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

4
@यर, यदि आपको चेक किए गए अपवाद पसंद नहीं हैं, तो "फेंकना नया रनटाइम एक्ससेप्शन (" हम उम्मीद नहीं करते थे कि जब Foo.bar () ", e) कर रहे हों" और इसके साथ किया जाए।
थोरबजर्न रेवन एंडरसन

4
@ ThorbjørnRavnAndersen: जावा में एक मौलिक डिजाइन की कमजोरी, जो .net दुर्भाग्य से कॉपी की गई है, यह है कि यह अपवाद के प्रकार का उपयोग करता है, क्योंकि दोनों का प्राथमिक तरीका यह तय करने के लिए है कि क्या इस पर कार्य किया जाना चाहिए, और सामान्य प्रकार को इंगित करने का प्राथमिक साधन। यह गलत हो गया, जब वास्तव में दो मुद्दे काफी हद तक रूढ़िवादी हैं। जो मायने रखता है वह गलत नहीं है, लेकिन राज्य की वस्तुएं क्या हैं। आगे, दोनों .net और जावा डिफ़ॉल्ट रूप से यह मान लेते हैं कि अपवाद पर काम करना और हल करना आम तौर पर एक ही बात है, जब वास्तव में वे अक्सर अलग होते हैं।
सुपरकैट

20

मैं शुरू में आपके साथ सहमत था, क्योंकि मैं हमेशा जाँच किए गए अपवादों के पक्ष में रहा हूं, और सोचने लगा कि मुझे .net अपवादों को पसंद नहीं करना क्यों पसंद है। लेकिन तब मुझे एहसास हुआ कि मैं चेक किए गए अपवादों की तरह प्रभावित नहीं करता।

आपको सवाल का जवाब देने के लिए, हां, मुझे स्टैक के निशान दिखाने के लिए मेरे कार्यक्रम पसंद हैं, अधिमानतः वास्तव में बदसूरत वाले। मैं चाहता हूं कि एप्लिकेशन आपको सबसे खराब त्रुटि संदेशों में से एक भयानक ढेर में विस्फोट करे, जिसे आप कभी भी देखना चाहते हैं।

और इसका कारण है, क्योंकि अगर ऐसा होता है, तो मुझे इसे ठीक करना होगा, और मुझे इसे ठीक करना होगा। मैं तुरंत जानना चाहता हूं कि कोई समस्या है।

आप वास्तव में अपवादों को कितनी बार संभालते हैं? मैं अपवादों को पकड़ने की बात नहीं कर रहा हूँ - मैं उन्हें संभालने की बात कर रहा हूँ? निम्नलिखित लिखना बहुत आसान है:

try {
  thirdPartyMethod();
} catch(TPException e) {
  // this should never happen
}

और मुझे पता है कि आप यह कह सकते हैं कि यह बुरा अभ्यास है, और यह कि 'उत्तर' अपवाद के साथ कुछ करने के लिए है (मुझे लॉग इन करें, इसे लॉग इन करें?), लेकिन रियल वर्ल्ड (tm) में, अधिकांश प्रोग्रामर अभी नहीं करते हैं यह।

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


जावा आपको इस प्रकार का काम करने के लिए प्रोत्साहित करता है, ताकि आपको हर प्रकार के हस्ताक्षर में हर प्रकार के अपवाद को जोड़ना न पड़े।
yfeldblum

17
मजेदार .. जब से मैंने अपवादों को सही ढंग से जांचा और सही ढंग से उनका इस्तेमाल किया, मेरे कार्यक्रमों ने आपके चेहरे के ग्राहक असंतोष के भारी भाप के ढेर में उड़ना बंद कर दिया। यदि विकसित करते समय आपके पास बड़े बदसूरत खराब स्टैक ट्रेस हैं, तो ग्राहक उन्हें भी प्राप्त करने के लिए बाध्य है। D'love उसका चेहरा देखने के लिए जब वह ArrayIndexOutOfBoundsException को देखता है, तो एक छोटे से ट्रे नोट के बजाय उसके दुर्घटनाग्रस्त सिस्टम पर एक मील के उच्च स्टैक ट्रेस के साथ कहा जाता है कि बटन XYZ के लिए कलर कॉन्फिग को पॉज़ नहीं किया जा सकता है, इसलिए इसके बजाय डिफ़ॉल्ट रूप से सॉफ़्टवेयर खुशी से गुनगुनाते हुए इस्तेमाल किया गया था। साथ
न्यूटोपियन

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

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

1
आप यहां जिन अपवादों के बारे में बात कर रहे हैं RuntimeExceptions, वे वास्तव में हैं जिन्हें आपको पकड़ने की जरूरत नहीं है, और मैं मानता हूं कि आपको कार्यक्रम को उड़ाने देना चाहिए। अपवादों को आपको हमेशा पकड़ना चाहिए और संभालना चाहिए जैसे कि अपवाद हैं IOException। यदि आपको एक मिलता है IOException, तो आपके कोड में कुछ भी नहीं है; आपके प्रोग्राम को सिर्फ इसलिए नहीं उड़ाना चाहिए क्योंकि वहाँ एक नेटवर्क हिचकी थी।
चाचीओमैटिकनेक्सस

20

आलेख प्रभावी जावा अपवाद स्पष्ट रूप से अनियंत्रित का उपयोग करने के लिए और कब जाँच अपवादों का उपयोग करने के लिए स्पष्ट करता है। मुख्य बिंदुओं को उजागर करने के लिए उस लेख के कुछ उद्धरण यहां दिए गए हैं:

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

दोष: एक अनियोजित स्थिति जो किसी विधि को उसके इच्छित उद्देश्य को प्राप्त करने से रोकती है जिसे विधि के आंतरिक कार्यान्वयन के संदर्भ के बिना वर्णित नहीं किया जा सकता है।

(एसओ तालिकाओं की अनुमति नहीं देता है, इसलिए आप मूल पृष्ठ से निम्नलिखित पढ़ना चाह सकते हैं ...)

आकस्मिकता

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

दोष

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

मुझे पता है कि उनका उपयोग कब करना है, मैं जानना चाहता हूं कि जो लोग उस सलाह का पालन नहीं करते हैं ... उस सलाह का पालन नहीं करते हैं :-)
TofuBeer

प्रोग्रामिंग बग क्या हैं और उन्हें उपयोग के बग से कैसे अलग किया जाए ? क्या यह एक प्रोग्रामिंग बग है यदि उपयोगकर्ता प्रोग्राम के लिए गलत तर्क देता है? जावा बिंदु से यह कोई प्रोग्रामिंग बग नहीं हो सकता है, लेकिन शेल स्क्रिप्ट बिंदु से यह एक प्रोग्रामिंग बग है। तो अमान्य तर्क क्या हैं args[]? वे एक आकस्मिकता या एक गलती है?
ceving

3
@TofuBeer - क्योंकि जावा लाइब्रेरी डिज़ाइनरों ने सभी प्रकार की अपरिवर्तनीय निम्न-स्तरीय विफलताओं को चुना, जब उन्हें स्पष्ट रूप से अनियंत्रित होना चाहिए था तब अपवादों की जाँच की । FileNotFound एकमात्र IOException है, जिसे उदाहरण के लिए जाँचना चाहिए। JDBC के संबंध में - केवल डेटाबेस से जुड़ना, यथोचित रूप से एक आकस्मिकता माना जा सकता है । अन्य सभी SQLException विफलताओं और अनियंत्रित होना चाहिए था । त्रुटि से निपटने को "व्यापार" या "अनुरोध" स्तर पर सही ढंग से होना चाहिए - "जल्दी फेंक, देर से पकड़" सर्वोत्तम अभ्यास देखें। चेक किए गए अपवाद उस के लिए एक बाधा हैं।
थॉमस डब्ल्यू

1
आपके तर्क में एक बहुत बड़ा दोष है। "आकस्मिकता" को अपवादों के माध्यम से नहीं, बल्कि व्यवसाय कोड और विधि वापसी मूल्यों के माध्यम से नियंत्रित किया जाना चाहिए। अपवाद हैं, जैसा कि शब्द कहता है, विशेष स्थितियों, इसलिए दोष।
मट्टियो मोस्का

@MatteoMosca त्रुटि वापसी कोड की उपेक्षा की जाती है और यह उन्हें अयोग्य ठहराने के लिए पर्याप्त है। वास्तव में, कुछ भी असामान्य कैन्टीन केवल स्टैक में कहीं और संभाला जा सकता है और यह अपवादों के लिए उपयोग मामला है। मैं File#openInputStreamलौटने की तरह कुछ कल्पना कर सकता था Either<InputStream, Problem>- अगर आपका मतलब है, तो हम सहमत हो सकते हैं।
Maaartinus

19

संक्षेप में:

अपवाद एक API डिज़ाइन प्रश्न है। -- न आधिक न कम।

जाँच किए गए अपवादों के लिए तर्क:

यह समझने के लिए कि जाँच किए गए अपवाद अच्छी बात क्यों नहीं हो सकते हैं, आइए प्रश्न को चारों ओर घुमाएं और पूछें: जब अपवादों की जाँच आकर्षक या क्यों की जाती है, तो आप यह क्यों चाहेंगे कि कंपाइलर अपवादों की घोषणा को लागू करें?

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

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

हालांकि वास्तविकता में, कभी-कभी एक पैकेज com.acmeकेवल AcmeExceptionविशिष्ट उपवर्गों के बजाय फेंकता है । फिर कॉल करने वालों को संभालने, घोषित करने या फिर से संकेत देने की आवश्यकता होती है AcmeExceptions, लेकिन फिर भी यह निश्चित नहीं हो सकता है कि क्या AcmeFileNotFoundErrorहुआ या क्या हुआ AcmePermissionDeniedError

इसलिए यदि आप केवल एक में रुचि रखते हैं AcmeFileNotFoundError, तो समाधान ACME प्रोग्रामर के साथ एक सुविधा अनुरोध दर्ज करना और उन्हें लागू करना, घोषित करना और दस्तावेज़ करना है जो उपवर्ग का है AcmeException

तो परवाह क्यों?

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

परिणामस्वरूप, बिना जाँच किए गए अपवादों की भाषा आमतौर पर बहुत खराब नहीं होती है। प्रोग्रामर को एक के Errorबजाय एक सामान्य वर्ग के अनिर्दिष्ट उदाहरणों को फेंकने के लिए लुभाया जा सकता है AcmeException, लेकिन अगर वे अपने एपीआई गुणवत्ता के बारे में बिल्कुल परवाह करते हैं, तो वे एक के AcmeFileNotFoundErrorबाद एक परिचय देना सीखेंगे ।

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

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

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


4
आपका तर्क खुद के खिलाफ तर्क देता है। यदि "कभी-कभी आपको एक अपवाद को पकड़ने की आवश्यकता होती है" और एपीआई गुणवत्ता अक्सर खराब होती है, तो बिना जांचे गए अपवादों के आपको पता नहीं चलेगा कि क्या डिजाइनर ने दस्तावेज की उपेक्षा की कि एक निश्चित विधि एक अपवाद को फेंकती है जिसे पकड़ने की आवश्यकता है। जोड़े कि AcmeExceptionबजाय फेंकने AcmeFileNotFoundErrorऔर सौभाग्य से पता लगा कि आपने क्या गलत किया और आपको इसे पकड़ने की आवश्यकता कहां है। जाँच किए गए अपवाद प्रोग्रामर्स को खराब एपीआई डिज़ाइन के विरुद्ध सुरक्षा का एक माध्यम प्रदान करते हैं।
ईवा

1
जावा लाइब्रेरी डिज़ाइन में गंभीर गलतियाँ हुईं। 'जांचे गए अपवाद' पूर्वानुमेय और पुनर्प्राप्ति योग्य आकस्मिकताओं के लिए थे - जैसे कि फ़ाइल नहीं मिली, कनेक्ट करने में विफलता। वे निम्न-स्तरीय प्रणालीगत विफलता के लिए कभी भी अनुकूल या अनुकूल नहीं थे। किसी फ़ाइल को जाँच के लिए खोलने के लिए मजबूर करना ठीक होता, लेकिन किसी भी बाइट को लिखने में विफलता के लिए कोई समझदार पुनर्प्राप्ति या पुनर्प्राप्ति नहीं होती है / SQL क्वेरी आदि निष्पादित करना। पुनर्प्राप्ति या पुनर्प्राप्ति को "व्यवसाय" या "अनुरोध" पर सही ढंग से नियंत्रित किया जाता है "स्तर, जो अपवादों की जाँच करते हैं, व्यर्थ को कठिन बनाते हैं। literatejava.com/exception/…
थॉमस डब्ल्यू

17

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

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

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

यह सब प्राथमिकता और डेवलपर कौशल का विषय है। प्रोग्रामिंग और एरर हैंडलिंग के दोनों तरीके समान रूप से प्रभावी (या अप्रभावी) हो सकते हैं, इसलिए मैं यह नहीं कहूंगा कि द वन वे है।

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


6
और यह करने के लिए। मेरे लिए वे एक अनुबंध का एक अनिवार्य हिस्सा हैं। एपीआई प्रलेखन में विस्तृत होने के बिना, मैं जल्दी से त्रुटि परिदृश्य की संभावना जान सकता हूं।
वेन हार्टमैन

2
इस बात से सहमत। जब मैंने नेटवर्क कॉल करने का प्रयास किया तो मैंने एक बार .Net में चेक किए गए अपवादों की आवश्यकता का अनुभव किया। यह जानते हुए कि एक नेटवर्क हिचकी किसी भी क्षण हो सकती है, मुझे एपीआई के पूरे प्रलेखन के माध्यम से पढ़ना था यह पता लगाने के लिए कि यह अपवाद क्या है कि मुझे उस परिदृश्य के लिए विशेष रूप से पकड़ने की आवश्यकता है। अगर C # अपवादों की जाँच करता तो मुझे तुरंत पता चल जाता। अन्य सी # डेवलपर्स शायद बस एक साधारण नेटवर्क त्रुटि से ऐप को क्रैश कर देंगे।
anxiomaticNexus

13

अपवाद श्रेणियां

जब मैं अपवादों के बारे में बात करता हूं तो मैं हमेशा एरिक लिपर्ट के वैक्सिंग अपवादों वाले ब्लॉग लेख का संदर्भ देता हूं । वह इन श्रेणियों में अपवाद रखता है:

  • घातक - ये अपवाद आपकी गलती नहीं हैं : आप तब रोक नहीं सकते हैं, और आप समझदारी से उन्हें संभाल नहीं सकते हैं। उदाहरण के लिए, OutOfMemoryErrorया ThreadAbortException
  • हड्डीवाला - ये अपवाद आपकी गलती हैं : आपको उन्हें रोकना चाहिए था, और वे आपके कोड में बग का प्रतिनिधित्व करते हैं। उदाहरण के लिए, ArrayIndexOutOfBoundsException, NullPointerExceptionया किसी IllegalArgumentException
  • Vexing - ये अपवाद असाधारण नहीं हैं , आपकी गलती नहीं है, आप उन्हें रोक नहीं सकते हैं, लेकिन आपको उनसे निपटना होगा। वे अक्सर एक दुर्भाग्यपूर्ण डिजाइन निर्णय का परिणाम है, इस तरह फेंक के रूप में कर रहे हैं NumberFormatExceptionसे Integer.parseIntएक प्रदान करने के बजाय Integer.tryParseIntविधि है कि पार्स विफलता पर एक बूलियन झूठी देता है।
  • बहिर्जात - ये अपवाद आमतौर पर असाधारण हैं , आपकी गलती नहीं है, आप (यथोचित) उन्हें रोक नहीं सकते हैं, लेकिन आपको उन्हें संभालना होगा । उदाहरण के लिए, FileNotFoundException

एक एपीआई उपयोगकर्ता:

  • घातक या हड्डी वाले अपवादों को नहीं संभालना चाहिए
  • चाहिए संभाल अप्रिय अपवाद हैं, लेकिन वे एक आदर्श एपीआई में घटित नहीं करना चाहिए।
  • बहिर्जात अपवादों को संभालना चाहिए

अपवादों की जाँच की

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

चूंकि एक एपीआई में वेजिंग अपवाद मौजूद नहीं होना चाहिए, केवल इन बहिर्जात अपवादों को विधि के अनुबंध का हिस्सा होने के लिए अपवादों की जांच करनी चाहिए । अपेक्षाकृत कुछ अपवाद बहिर्जात हैं , इसलिए किसी भी एपीआई में अपेक्षाकृत कुछ अपवाद होने चाहिए।

एक जाँच अपवाद एक अपवाद है जिसे संभाला जाना चाहिए । एक अपवाद को संभालना उतना ही सरल हो सकता है जितना इसे निगलने में। वहाँ! अपवाद को नियंत्रित किया जाता है। अवधि। अगर डेवलपर इसे इस तरह से हैंडल करना चाहता है, तो ठीक है। लेकिन वह अपवाद को नजरअंदाज नहीं कर सकता, और चेतावनी दी गई है।

एपीआई समस्याएं

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

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

निष्कर्ष

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

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


और पदानुक्रम नहीं होने से उनका दुरुपयोग करते हैं।
टोफूबीर

1
FileNotFound और JDBC / नेटवर्क कनेक्शन स्थापित करना आकस्मिकता है और अपवादों की जाँच करना सही है, क्योंकि ये अनुमानित और (संभव) पुनर्प्राप्त करने योग्य हैं। अधिकांश अन्य IOException, SQLException, RemoteException आदि अप्रत्याशित और अप्राप्य विफलताएं हैं , और रनटाइम अपवाद होना चाहिए था गलत तरीके से जावा लाइब्रेरी डिज़ाइन के कारण, हम सभी इस गलती से प्रभावित हुए हैं और अब ज्यादातर स्प्रिंग एंड हाइबरनेट का उपयोग कर रहे हैं (जिन्हें अपना डिज़ाइन सही मिला है)।
थॉमस डब्ल्यू

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

6

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

तो, एक चेक किए गए अपवाद को हटा देता है, जैसे कि C # में किया गया था, फिर कैसे कोई प्रोग्रामेटिक और संरचनात्मक रूप से त्रुटि की संभावना को बता सकता है? क्लाइंट कोड को कैसे सूचित किया जाए कि इस तरह की त्रुटियां हो सकती हैं और इससे निपटा जाना चाहिए?

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

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

कई लोगों ने तर्क दिया है कि फ़ाइल को लोड करने में सक्षम नहीं होना प्रक्रिया के लिए लगभग हमेशा दुनिया का अंत था और इसे एक भयानक और दर्दनाक मौत मरना होगा। तो हाँ .. यकीन है कि ... ठीक है .. आप कुछ के लिए एक एपीआई का निर्माण करते हैं और यह कुछ बिंदु पर फ़ाइल लोड करता है ... मैं उक्त एपीआई के उपयोगकर्ता के रूप में केवल जवाब दे सकता हूं ... "आप कौन हैं यह तय करने के लिए जब मेरे कार्यक्रम क्रैश होना चाहिए! " निश्चित रूप से उस विकल्प को देखते हुए, जहां अपवादों को टटोला जाता है और कोई निशान नहीं छोड़ते या EletroFlabbingChunkFluxManifoldChuggingException स्टैक ट्रेस के साथ गहरे मैरिएना ट्रेंच की तुलना में मैं बिना किसी हिचकिचाहट के बाद ले जाएगा, लेकिन इसका मतलब यह है कि यह अपवाद से निपटने के लिए वांछनीय तरीका है। ? क्या हम कहीं बीच में नहीं हो सकते हैं, जहां अपवाद को फिर से लागू किया जाएगा और हर बार इसे अमूर्तता के एक नए स्तर में बदल दिया जाएगा ताकि यह वास्तव में कुछ का मतलब हो?

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

यदि हम चेक किए गए अपवाद को समाप्त कर देते हैं तो हम फ़ंक्शंस के लिए वापसी प्रकार को भी समाप्त कर सकते हैं और हमेशा एक "anytype" चर लौटा सकते हैं ... जो जीवन को इतना सरल बना देगा अब ऐसा नहीं होगा?


2
चेक किए गए अपवाद उपयोगी होंगे यदि कहने का कोई घोषणात्मक साधन था, तो ब्लॉक के भीतर कोई भी विधि कॉल कुछ (या किसी भी) चेक किए गए अपवादों को फेंकने की उम्मीद नहीं है, और इस तरह के किसी भी अपवाद को स्वचालित रूप से लपेटा जाना चाहिए और फिर से फेंकना चाहिए। वे और भी उपयोगी हो सकते हैं यदि उन विधियों पर कॉल करें जिन्हें कॉल-स्पीड / रिटर्न ऑफ चेक-अपवाद गति के रूप में ट्रेड किए गए अपवादों को फेंकने की जाँच के रूप में घोषित किया गया था (ताकि अपेक्षित अपवादों को सामान्य प्रोग्राम फ्लो के रूप में तेजी से नियंत्रित किया जा सके)। हालांकि, वर्तमान में न तो स्थिति लागू होती है।
सुपरकाट

6

वास्तव में, एक तरफ अपवादों की जाँच आपके कार्यक्रम की मजबूती और शुद्धता को बढ़ाती है (आप अपने इंटरफेस की सही घोषणा करने के लिए मजबूर हैं-अपवाद एक विधि फेंकता मूल रूप से एक विशेष वापसी प्रकार हैं)। दूसरी ओर आप इस समस्या का सामना करते हैं, क्योंकि अपवाद "बबल अप" के बाद से, बहुत बार आपको कई सारे तरीकों को बदलने की आवश्यकता होती है (सभी कॉल करने वाले, और कॉल करने वाले के कॉलर्स, और इसी तरह) जब आप अपवादों को बदलते हैं। विधि फेंकता है।

जावा में जांचे गए अपवाद बाद की समस्या को हल नहीं करते हैं; C # और VB.NET ने नहाने के पानी से बच्चे को बाहर निकाल दिया।

मध्य सड़क पर ले जाने वाला एक अच्छा तरीका इस OOPSLA 2005 पेपर (या संबंधित तकनीकी रिपोर्ट ) में वर्णित है ।

संक्षेप में, यह आपको कहने की अनुमति देता है: method g(x) throws like f(x)जिसका अर्थ है कि जी सभी अपवादों को फेंकता है। वोइला, कैस्केडिंग परिवर्तन समस्या के बिना अपवादों की जाँच की।

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


5

यह चेक किए गए अपवादों की शुद्ध अवधारणा के खिलाफ एक तर्क नहीं है, लेकिन उनके लिए वर्ग पदानुक्रम जावा का उपयोग एक सनकी शो है। हम हमेशा चीजों को केवल "अपवाद" कहते हैं - जो सही है, क्योंकि भाषा विनिर्देश उन्हें कहते हैं - लेकिन प्रकार सिस्टम में नाम और प्रतिनिधित्व कैसे एक अपवाद है?

कक्षा से Exceptionएक कल्पना करता है? खैर नहीं, क्योंकि Exceptionएस अपवाद हैं, और इसी तरह अपवाद हैं Exception, उन अपवादों को छोड़कर जो एस नहीं हैं Exception, क्योंकि अन्य अपवाद वास्तव में Errorएस हैं, जो अन्य प्रकार के अपवाद हैं, एक प्रकार का अतिरिक्त-असाधारण अपवाद जो कभी नहीं होने चाहिए। जब यह होता है, और जो आपको कभी नहीं छोड़ना चाहिए, कभी-कभी आपको करना पड़ता है। सिवाय इसके सभी नहीं है क्योंकि आप अन्य अपवादों को भी परिभाषित कर सकते हैं जो न तो Exceptions हैं और न ही Errorकेवल Throwableअपवाद हैं।

इनमें से कौन सी "जाँच" अपवाद हैं? Throwables अपवादों की जाँच की जाती है, सिवाय इसके कि वे भी Errors हैं, जो अनियंत्रित अपवाद हैं, और फिर वहाँ Exceptions हैं, जो कि s भी Throwableहैं और जाँच किए गए अपवाद के मुख्य प्रकार हैं, सिवाय इसके कि एक अपवाद भी है, जो कि यदि वे RuntimeExceptionएस भी हैं , क्योंकि यह अनियंत्रित अपवाद का दूसरा प्रकार है।

किसलिए हैं RuntimeException? वैसे, जैसा कि नाम से ही स्पष्ट है, वे अपवाद हैं, सभी Exceptionएस की तरह , और वे रन-टाइम पर होते हैं, वास्तव में सभी अपवादों की तरह, सिवाय इसके कि RuntimeExceptionअन्य रन-टाइम Exceptionएस की तुलना में असाधारण हैं क्योंकि वे इसके अलावा होने वाले नहीं हैं जब आप कुछ मूर्खतापूर्ण त्रुटि करते हैं, हालांकि RuntimeExceptionएस कभी नहीं होते हैं Error, इसलिए वे उन चीजों के लिए हैं जो असाधारण रूप से गलत हैं लेकिन जो वास्तव में Errorएस नहीं हैं । सिवाय RuntimeErrorException, जो वास्तव में एक के RuntimeExceptionलिए है Error। लेकिन सभी अपवादों को वैसे भी गलत परिस्थितियों का प्रतिनिधित्व नहीं करना चाहिए? हाँ, उन सभी को। सिवाय ThreadDeath, एक असाधारण अपवाद के अपवाद के रूप में, प्रलेखन बताता है कि यह एक "सामान्य घटना" है और यह कि 'Error

वैसे भी, चूंकि हम सभी अपवादों को बीच में विभाजित कर रहे हैं Error(जो कि असाधारण निष्पादन अपवादों के लिए हैं, इसलिए अनियंत्रित हैं) और Exceptionएस (जो कम असाधारण निष्पादन त्रुटियों के लिए हैं, इसलिए जब वे नहीं होते हैं, तब छोड़कर जाँच की जाती है), अब हमें दो की आवश्यकता है कई अपवादों में से प्रत्येक के विभिन्न प्रकार। इसलिए हम जरूरत IllegalAccessErrorऔर IllegalAccessExceptionहै, और InstantiationErrorऔर InstantiationException, और NoSuchFieldErrorऔर NoSuchFieldException, और NoSuchMethodErrorऔर NoSuchMethodException, और ZipErrorऔर ZipException

सिवाय इसके कि जब एक अपवाद की जाँच की जाती है, तब भी हमेशा कंपाइलर को धोखा देने और बिना जाँच किए उसे फेंकने के तरीके (काफी आसान) होते हैं। यदि आप ऐसा करते हैं कि आपको UndeclaredThrowableExceptionअन्य मामलों को छोड़कर, जहां यह एक UnexpectedException, या एक UnknownException(जो कि असंबंधित है UnknownError, जो केवल "गंभीर अपवाद" के लिए है), या एक ExecutionException, या एक InvocationTargetException, या एक के रूप में फेंक सकता है ExceptionInInitializerError

ओह, और हमें जावा 8 के स्नैज़ी नए को नहीं भूलना चाहिए UncheckedIOException, जो कि एक RuntimeExceptionअपवाद है जिसे आपको IOExceptionI / O त्रुटियों के कारण जाँच किए गए अपवादों को लपेटकर अपवाद जाँच अवधारणा को फेंकने के लिए डिज़ाइन किया गया है (जो IOErrorअपवादों का कारण नहीं है, हालांकि यह मौजूद है भी) जो असाधारण रूप से संभालना मुश्किल है और इसलिए आपको जांचने की आवश्यकता नहीं है।

धन्यवाद जावा!


2
जहां तक ​​मैं कह सकता हूं, यह जवाब केवल यह कहता है कि "जावा के अपवाद एक गड़बड़ हैं" पूरी तरह से विडंबनापूर्ण, मजाकिया तरीके से। ऐसा नहीं लगता है कि यह स्पष्ट नहीं है कि प्रोग्रामर यह समझने की कोशिश करने से बचते हैं कि इन चीजों को कैसे काम करना चाहिए। इसके अलावा, वास्तविक जीवन के मामलों में (कम से कम मेरे पास एक सौदा करने का मौका था), अगर प्रोग्रामर जानबूझकर अपने जीवन को कठिन बनाने की कोशिश नहीं करते हैं, तो अपवाद कहीं भी जटिल नहीं हैं जितना कि आप वर्णित हैं।
CptBartender

5

समस्या

अपवाद संचालन तंत्र के साथ सबसे खराब समस्या यह है कि यह बड़े पैमाने पर कोड दोहराव का परिचय देता है ! आइए ईमानदार रहें: 95% परियोजनाओं में अधिकांश समय जो कि डेवलपर्स को वास्तव में अपवाद के साथ करने की आवश्यकता होती है, उसे किसी भी तरह उपयोगकर्ता को संवाद करना है (और, कुछ मामलों में, विकास टीम को भी, जैसे कि एक ई भेजकर। -स्टैक ट्रेस के साथ)। इसलिए आमतौर पर कोड की एक ही लाइन / ब्लॉक का उपयोग हर उस स्थान पर किया जाता है जहां अपवाद को नियंत्रित किया जाता है।

मान लेते हैं कि हम प्रत्येक कैच ब्लॉक में कुछ प्रकार के चेक किए गए अपवादों के लिए सरल लॉगिंग करते हैं:

try{
   methodDeclaringCheckedException();
}catch(CheckedException e){
   logger.error(e);
}

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

एक पल रुको ... क्या हम वास्तव में कोड में उन सभी सैकड़ों स्थानों को संपादित करने जा रहे हैं ?! आप मेरी बात :-)

समाधान

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

try{
    methodDeclaringCheckedException();
}catch(CheckedException e){
    exceptionHandler.handleError(e);
}

अब अपने अपवाद हैंडलिंग को अनुकूलित करने के लिए हमें केवल एक ही स्थान (EH कोड) में कोड को बदलना होगा।

बेशक अधिक जटिल मामलों के लिए हम ईएच और लीवरेज सुविधाओं के कई उपवर्गों को लागू कर सकते हैं जो हमारे डीआई ढांचे हमें प्रदान करते हैं। हमारे DI फ्रेमवर्क कॉन्फ़िगरेशन को बदलकर हम आसानी से EH कार्यान्वयन को विश्व स्तर पर स्विच कर सकते हैं या विशेष अपवाद से निपटने की जरूरतों (उदाहरण के लिए Guice @ नामांकित एनोटेशन का उपयोग करके) के साथ कक्षाओं के लिए EH के विशिष्ट कार्यान्वयन प्रदान कर सकते हैं।

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

अंतिम एक बात

पिछले नहीं बल्कि कम से कम, ऐसा लग सकता है कि एक ही तरह के केंद्रीकरण को हमारे अपवादों को "ऊपर" पास करके प्राप्त किया जा सकता है जब तक कि वे कुछ शीर्ष स्तर के अपवाद से निपटने वाले वर्ग तक नहीं पहुंचते। लेकिन इससे हमारे तरीकों के कोड और हस्ताक्षरों की अव्यवस्था होती है और इस धागे में दूसरों द्वारा उल्लिखित रखरखाव समस्याओं का परिचय दिया जाता है।


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

2
@ceving हाँ, यह सिद्धांत में सभी अच्छे और सच्चे हैं। लेकिन अब चलिए वापस अभ्यास शब्द पर आते हैं। कृपया वास्तव में ईमानदारी से जवाब दें कि आप इसे अपने वास्तविक शब्द प्रोजेक्ट में कितनी बार करते हैं? catchइस वास्तविक परियोजना में ब्लॉक का कौन सा हिस्सा अपवादों के साथ वास्तव में "उपयोगी" है? 10% अच्छा होगा। सामान्य समस्याएं जो अपवाद उत्पन्न करती हैं, वे उस फ़ाइल से कॉन्फ़िगरेशन पढ़ने की कोशिश कर रही हैं जो मौजूद नहीं है, OutOfMemoryErrors, NullPointerException, डेटाबेस बाधा अखंडता त्रुटि आदि, आदि। क्या आप वास्तव में उन सभी को अच्छी तरह से पुनर्प्राप्त करने की कोशिश कर रहे हैं? मुझे आप पर विश्वास नहीं है :)। अक्सर ठीक होने का कोई उपाय नहीं है।
पियोत्र सोबस्ज़क

3
@PiotrSobczyk: यदि कोई प्रोग्राम पर्याप्त अनुरोध के परिणामस्वरूप कुछ कार्रवाई करता है, और ऑपरेशन कुछ फैशन में विफल रहता है, जिसने सिस्टम स्थिति में कुछ भी क्षतिग्रस्त नहीं किया है, तो उपयोगकर्ता को सूचित करना कि ऑपरेशन पूरा नहीं किया जा सकता है एक पूरी तरह से उपयोगी है स्थिति को संभालने का तरीका। C # और .net में अपवादों की सबसे बड़ी विफलता यह है कि यह पता लगाने का कोई सुसंगत तरीका नहीं है कि सिस्टम स्थिति में कुछ भी क्षतिग्रस्त हो गया है या नहीं।
सुपरकैट

4
सही है, @PiotrSobczyk। अधिकतर, अपवाद के जवाब में कार्रवाई करने के लिए एकमात्र सही कार्रवाई लेनदेन रोलबैक करना और त्रुटि प्रतिक्रिया वापस करना है। "अपवाद को हल करने" के विचार का अर्थ है कि हमारे पास ऐसा ज्ञान और अधिकार नहीं है (और नहीं होना चाहिए), और इनकैप्सुलेशन का उल्लंघन करना। यदि हमारा एप्लिकेशन DB नहीं है, तो हमें DB को ठीक करने का प्रयास नहीं करना चाहिए । सफाई से असफल होना और गलत डेटा लिखने से बचना, सीडिंग करना काफी उपयोगी है
थॉमस डब्ल्यू

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

4

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


4

C2.com पर मेरा राइटअप अभी भी ज्यादातर अपने मूल रूप से अपरिवर्तित है: CheckedExceptionAreIncompatibleWithVisitorPattern

संक्षेप में:

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

CheckedException की मौलिक धारणा सभी घोषित अपवादों को किसी भी बिंदु से फेंक दिया जा सकता है जो उस घोषणा के साथ एक विधि कहता है। VisitorPattern इस धारणा को दोषपूर्ण होने का खुलासा करता है।

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

अंतर्निहित समस्या के लिए:

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


1
आपके पास इंटरफ़ेस में DAGNodeException जैसी कोई चीज़ होनी चाहिए, फिर IOException को पकड़ें और इसे DAGNodeException में परिवर्तित करें: सार्वजनिक शून्य कॉल (DAGNode arg) DAGNodeException को फेंकता है;
टोफूबीर

2
@ टोफूबीर, यह बिल्कुल मेरी बात है। मुझे लगता है कि लगातार रैपिंग और अलिखित अपवादों को जाँच अपवादों को हटाने से भी बदतर है।
जोशुआ

2
वैसे हम पूरी तरह से असहमत हैं ... लेकिन आपका लेख अभी भी वास्तविक अंतर्निहित सवाल का जवाब नहीं देता है कि आप एक रनटाइम अपवाद को फेंकने पर उपयोगकर्ता को स्टैक ट्रेस प्रदर्शित करने से कैसे रोकते हैं।
टोफूबीर 1

1
@TofuBeer - जब यह विफल हो जाता है, तो उपयोगकर्ता को यह बताना विफल रहा कि यह सही है! "अशक्त 'या अपूर्ण / गलत डेटा के साथ" पेपर ओवर "की विफलता के अलावा आपके पास क्या विकल्प है? यह सफल होने पर झूठ बोलना एक झूठ है, जो सिर्फ चीजों को बदतर बनाता है। उच्च-विश्वसनीयता प्रणालियों में 25 वर्षों के अनुभव के साथ, रिट्री लॉजिक का उपयोग केवल सावधानीपूर्वक और जहां उचित हो, किया जाना चाहिए। मैं एक विज़िटर से यह उम्मीद करूंगा कि वह फिर से विफल हो जाए, चाहे आप उसे कितनी भी बार रिटायर कर लें। जब तक आप एक विमान नहीं उड़ा रहे हैं, उसी एल्गोरिथ्म के दूसरे संस्करण के लिए स्वैप करना अव्यावहारिक और अनुमानित है (और वैसे भी विफल हो सकता है)।
थॉमस डब्ल्यू

4

बस अनुत्तरित प्रश्न को संबोधित करने का प्रयास करने के लिए:

यदि आप अपवाद उपवर्गों के बजाय RuntimeException उपवर्गों को फेंकते हैं तो आपको कैसे पता चलेगा कि आप क्या पकड़ने वाले हैं?

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

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

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

यदि, हालांकि, मैं एक प्रोसेसिंग इंजन लिख रहा हूं, तो मैं संभवतः एक NPE की तरह XPathException (चेक किया गया) का इलाज करूंगा: मैं इसे वर्कर थ्रेड के शीर्ष तक चलने दूंगा, उस बैच के बाकी हिस्सों को छोड़ दूंगा, लॉग समस्या (या निदान के लिए एक समर्थन विभाग को भेजें) और समर्थन से संपर्क करने के लिए उपयोगकर्ता के लिए प्रतिक्रिया छोड़ दें।


2
बिल्कुल सही। आसान और सीधा, अपवाद-हैंडलिंग तरीका। जैसा कि डेव कहते हैं, सामान्य स्तर पर सही अपवाद-हैंडलिंग सामान्य रूप से की जाती है । "जल्दी फेंको, देर से पकड़ना" सिद्धांत है। जांचे गए अपवाद कठिन बनाते हैं।
थॉमस डब्ल्यू

4

यह लेख जावा मैंने कभी पढ़ा है में अपवाद हैंडलिंग पर पाठ का सबसे अच्छा टुकड़ा है।

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

मैं यहाँ बहुत अधिक लेख सामग्री का हवाला नहीं देना चाहता (इसे संपूर्ण रूप में पढ़ना सबसे अच्छा है) लेकिन इस धागे से अनियंत्रित अपवाद अधिवक्ताओं के अधिकांश तर्क शामिल हैं। विशेष रूप से यह तर्क (जो काफी लोकप्रिय लगता है) कवर किया गया है:

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

लेखक "प्रतिक्रियाएँ":

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

और मुख्य विचार या लेख है:

जब सॉफ़्टवेयर में त्रुटि से निपटने की बात आती है, तो केवल सुरक्षित और सही धारणा जो कभी भी हो सकती है, यह है कि विफलता हर सबरूटीन या मॉड्यूल में मौजूद हो सकती है!

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

इसलिए बहुत दुख की बात नहीं है कि इस महान लेख की खोज की जा रही है :-( मैं पूरी तरह से हर किसी की सलाह देता हूं जो संकोच करता है कि कौन सा दृष्टिकोण बेहतर है कि कुछ समय निकालें और इसे पढ़ें।


4

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

मूल अवधारणा में कभी शामिल नहीं किया गया था, प्रणालीगत और अप्राप्य विफलताओं की एक विशाल श्रृंखला को घोषित करने के लिए मजबूर करना था। इन विफलताओं को कभी भी जाँच अपवाद के रूप में घोषित किया जाना सही नहीं था।

आमतौर पर कोड में विफलताएं संभव हैं, और ईजेबी, वेब और स्विंग / एडब्ल्यूटी कंटेनर पहले से ही एक बाहरी "असफल अनुरोध" अपवाद-हैंडलर प्रदान करके इसे पूरा करते हैं। सबसे बुनियादी सही रणनीति लेन-देन को रोलबैक करना और एक त्रुटि वापस करना है।

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

"जाँच" अपवादों के खिलाफ सबसे बड़ा तर्क यह है कि अधिकांश अपवादों को तय नहीं किया जा सकता है। सरल तथ्य यह है, हमारे पास कोड / सबसिस्टम ही नहीं है जो टूट गया। हम कार्यान्वयन नहीं देख सकते, हम इसके लिए जिम्मेदार नहीं हैं, और इसे ठीक नहीं कर सकते।

यदि हमारा एप्लिकेशन DB नहीं है .. तो हमें DB को आज़माना नहीं चाहिए। यह इनकैप्सुलेशन के सिद्धांत का उल्लंघन करेगा ।

विशेष रूप से समस्याग्रस्त JDBC (SQLException) और RMI के क्षेत्र EJB (RemoteException) के लिए हुए हैं। मूल "चेक किए गए अपवाद" अवधारणा के अनुसार निर्धारण योग्य आकस्मिकताओं की पहचान करने के बजाय, इन व्यापक व्यापक प्रणालीगत विश्वसनीयता के मुद्दों को वास्तव में निर्धारण योग्य नहीं, व्यापक रूप से घोषित किया जाना चाहिए।

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

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

अंत में, "चेक अपवाद" एफपी कार्यात्मक प्रोग्रामिंग के साथ बहुत अधिक असंगत हैं।

"तुरंत संभालने" की उनकी जिद दोनों के साथ है "कैच लेट" अपवाद-हैंडलिंग सबसे अच्छा अभ्यास, और कोई भी एफपी संरचना जो लूप / नियंत्रण के प्रवाह को रोकती है।

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

एक अपवाद से निपटने के लिए सफाई से असफलता, सबसे बुनियादी सही रणनीति है। लेन-देन को वापस करना, त्रुटि लॉग करना और उपयोगकर्ता को "विफलता" प्रतिक्रिया की रिपोर्ट करना ध्वनि अभ्यास है - और सबसे महत्वपूर्ण बात, डेटाबेस के लिए गलत व्यापार डेटा को रोकना है।

अपवाद-हैंडलिंग के लिए अन्य रणनीतियाँ व्यवसाय, उपतंत्र या अनुरोध स्तर पर "पुनः प्रयास करें", "पुन: कनेक्ट करें" या "छोड़ें" हैं। ये सभी सामान्य विश्वसनीयता रणनीति हैं, और रनटाइम अपवादों के साथ अच्छी तरह से / बेहतर काम करती हैं।

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

देखें:
- http://literatejava.com/exception/checked-exception-javas-biggest-mistake/


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

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

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

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

1
अनुरोध सीमा या सबसे बाहरी हैंडलर पर "वास्तविक बग" रिपोर्ट करना खतरनाक क्यों है ??? मैं अक्सर सिस्टम एकीकरण और विश्वसनीयता में काम करता हूं, जहां सही विश्वसनीयता इंजीनियरिंग वास्तव में महत्वपूर्ण है, और ऐसा करने के लिए "अनियंत्रित अपवाद" दृष्टिकोण का उपयोग करें। मुझे वास्तव में यकीन नहीं है कि आप वास्तव में क्या बहस कर रहे हैं - ऐसा लगता है कि आप वास्तव में अनियंत्रित अपवाद तरीके से 3 महीने बिताना चाहते हैं, इसके लिए एक महसूस कर सकते हैं, और फिर शायद हम आगे चर्चा कर सकते हैं। धन्यवाद।
थॉमस डब्ल्यू

4

जैसा कि लोगों ने पहले ही बताया है, जावा बाइटकोड में चेक किए गए अपवाद मौजूद नहीं हैं। वे बस एक संकलक तंत्र हैं, अन्य वाक्यविन्यास जांचों के विपरीत नहीं। मैं जाँच किए गए अपवादों को बहुत देखता हूँ जैसे मैं कंपाइलर को एक निरर्थक स्थिति के बारे में शिकायत करते देखता हूँ if(true) { a; } b;:। यह मददगार है, लेकिन मैंने इस उद्देश्य को पूरा किया है, इसलिए मुझे आपकी चेतावनियों को नजरअंदाज करना चाहिए।

इस मामले का तथ्य यह है कि, आप प्रत्येक प्रोग्रामर को "सही काम करने" के लिए बाध्य करने में सक्षम नहीं होंगे, यदि आप चेक किए गए अपवादों को लागू करते हैं और बाकी सभी अब संपार्श्विक क्षति है, जो आपके द्वारा बनाए गए नियम के लिए आपसे नफरत करता है।

वहाँ बाहर खराब कार्यक्रमों को ठीक करें! उन्हें अनुमति न देने के लिए भाषा को ठीक करने का प्रयास न करें! अधिकांश लोगों के लिए, "अपवाद के बारे में कुछ करना" वास्तव में उपयोगकर्ता को इसके बारे में बता रहा है। मैं उपयोगकर्ता को अनियंत्रित अपवाद के बारे में भी बता सकता हूं, इसलिए अपने चेक किए गए अपवाद वर्गों को मेरे एपीआई से बाहर रखें।


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

3

चेक किए गए अपवादों के साथ एक समस्या यह है कि अपवाद अक्सर इंटरफ़ेस के तरीकों से जुड़े होते हैं यदि उस इंटरफ़ेस का एक भी कार्यान्वयन इसका उपयोग करता है।

चेक किए गए अपवादों के साथ एक और समस्या यह है कि उनका दुरुपयोग किया जाता है। इसका सटीक उदाहरण java.sql.Connection's close()विधि में है। यह एक फेंक सकता है SQLException, भले ही आपने पहले ही स्पष्ट रूप से कहा हो कि आप कनेक्शन के साथ कर रहे हैं। कौन सी जानकारी बंद हो सकती है () संभवतः बताएं कि आप किस बारे में परवाह करेंगे?

आमतौर पर, जब मैं बंद () एक कनेक्शन *, यह कुछ इस तरह दिखता है:

try {
    conn.close();
} catch (SQLException ex) {
    // Do nothing
}

इसके अलावा, मुझे विभिन्न पार्स विधियों और NumberFormatException पर आरंभ नहीं करें ... .NET का ट्रायपर्स, जो अपवादों को नहीं फेंकता है, जावा का उपयोग करने के लिए वापस जाने के लिए दर्दनाक होना बहुत आसान है (हम जावा और दोनों का उपयोग करते हैं) C # जहां मैं काम करता हूं)।

*एक अतिरिक्त टिप्पणी के रूप में, एक PooledConnection's Connection.close () भी एक कनेक्शन को बंद नहीं करता है , लेकिन आपको अभी भी एक चेक अपवाद होने के कारण SQLException को पकड़ना होगा।


2
सही है, ड्राइवरों में से कोई भी ... सवाल यह है कि "प्रोग्रामर को क्यों ध्यान रखना चाहिए?" के रूप में वह वैसे भी डेटाबेस तक पहुँचने किया है। डॉक्स आपको यह भी चेतावनी देता है कि आपको कॉल करने से पहले हमेशा () या रोलबैक (वर्तमान लेनदेन) करना चाहिए ()।
पॉवरलॉर्ड

बहुत से लोग सोचते हैं कि किसी फ़ाइल को बंद करना एक अपवाद नहीं हो सकता है ... stackoverflow.com/questions/588546/… क्या आप 100% निश्चित हैं कि ऐसे कोई मामले नहीं हैं जो कि मायने रखेंगे?
टोफूबीर

मैं 100% कुछ नहीं मामलों है कि यह देखते हैं कि कर रहा हूँ होगा मामला है और फोन करने वाले है कि नहीं होगा आज़माएं / कैच में डाल दिया।
मार्टिन

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

1
@PiotrSobczyk: यदि कोई लेन-देन शुरू करने के बाद किसी कनेक्शन को बंद करता है, लेकिन इसकी पुष्टि नहीं करता है और न ही इसे वापस रोल करता है, तो कुछ SQL ड्राइवर स्क्वॉव करेंगे। IMHO, स्क्वाकिंग चुपचाप समस्या को अनदेखा करने से बेहतर है, कम से कम उन मामलों में जहां स्क्वॉडिंग अन्य अपवादों को खो जाने का कारण नहीं होगा।
सुपरकैट

3

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

पतला लाभ बोझ लागत (विशेष रूप से बड़े, कम लचीले कोड आधारों, जहां लगातार इंटरफ़ेस हस्ताक्षर को संशोधित करना व्यावहारिक नहीं है) से आगे निकल जाता है।

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


2

मुझे लगता है कि यह एक उत्कृष्ट प्रश्न है और सभी तर्क संगत नहीं है। मुझे लगता है कि 3 पार्टी पुस्तकालयों को (सामान्य रूप से) अनियंत्रित अपवादों को फेंकना चाहिए । इसका मतलब है कि आप अपनी निर्भरता को लाइब्रेरी पर अलग कर सकते हैं (यानी आपको उनके अपवादों को फिर से फेंकना या फेंकना नहीं है Exception- आमतौर पर अच्छा अभ्यास)। स्प्रिंग का DAO परत इसका एक उत्कृष्ट उदाहरण है।

दूसरी ओर, कोर जावा एपीआई के अपवादों को सामान्य रूप से जांचा जाना चाहिए यदि वे कभी भी संभाले जा सकते हैं । FileNotFoundException(या मेरा पसंदीदा) लो InterruptedException। इन स्थितियों को लगभग हमेशा विशेष रूप से नियंत्रित किया जाना चाहिए (यानी आपकी प्रतिक्रिया आपकी प्रतिक्रिया InterruptedExceptionके समान नहीं है IllegalArgumentException)। तथ्य यह है कि आपके अपवादों की जाँच की जाती है, डेवलपर्स को यह सोचने के लिए मजबूर करते हैं कि क्या हालत संभाल सकने योग्य है या नहीं। (यह कहा, मैं शायद ही कभी InterruptedExceptionठीक से देखा है!)

एक और बात - RuntimeExceptionयह हमेशा नहीं होता है "जहां एक डेवलपर को कुछ गलत मिला है"। एक अवैध तर्क अपवाद को फेंक दिया जाता है जब आप कोशिश करते हैं और एक enumउपयोग करते हैं valueOfऔर enumउस नाम का कोई नाम नहीं होता है। यह जरूरी नहीं कि डेवलपर द्वारा एक गलती है!


1
हां, यह डेवलपर की गलती है। उन्होंने स्पष्ट रूप से सही नाम का उपयोग नहीं किया, इसलिए उन्हें वापस जाना होगा और अपना कोड ठीक करना होगा।
चाचीओमैटिकनेक्सस

@AxiomaticNexus कोई भी डेवलपर डेवलपर enumसदस्य नामों का उपयोग नहीं करता है , केवल इसलिए कि वे enumवस्तुओं का उपयोग करते हैं। तो एक गलत नाम केवल बाहर से आ सकता है, यह एक आयात फ़ाइल या जो कुछ भी हो। ऐसे नामों से निपटने का एक संभावित तरीका है MyEnum#valueOfIAE को कॉल करना और पकड़ना। एक अन्य तरीका पूर्व-भरे हुए का उपयोग करना है Map<String, MyEnum>, लेकिन ये कार्यान्वयन विवरण हैं।
मातरिनस 15

@maaartinus ऐसे मामले हैं जहां बाहर से आने वाले स्ट्रिंग के बिना एनम सदस्य के नाम का उपयोग किया जाता है। उदाहरण के लिए, जब आप गतिशील रूप से प्रत्येक के साथ कुछ करने के लिए सभी सदस्यों के माध्यम से लूप करना चाहते हैं। इसके अलावा, क्या स्ट्रिंग बाहर से आती है या नहीं अप्रासंगिक है। डेवलपर के पास वे सभी जानकारी हैं जिनकी आवश्यकता है, यह जानने के लिए कि "MyEnum # valueOf" में x स्ट्रिंग पास करने से पहले कोई त्रुटि होगी। "MyEnum # valueOf" में x स्ट्रिंग पास करना वैसे भी जब त्रुटि का कारण होगा, तो स्पष्ट रूप से विकास के हिस्से पर एक गलती होगी।
anxiomaticNexus

2

चेक किए गए अपवादों (joelonsoftware.com से) के खिलाफ यहाँ एक तर्क है:

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

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

3
+1 हालांकि आप अपने उत्तर में तर्क को संक्षेप में प्रस्तुत करना चाहते हैं? वे अदृश्य गैंडों की तरह हैं और पूरे कार्यक्रम के दौरान आपकी दिनचर्या के लिए जल्दी बाहर निकलते हैं।
MarkJ

13
यह सामान्य रूप से अपवाद के खिलाफ एक तर्क है।
आयनू जी। स्टेन मार्क

10
क्या आपने वास्तव में लेख पढ़ा है !! सबसे पहले वह सामान्य रूप से अपवादों के बारे में बात करता है, दूसरा खंड "वे स्रोत कोड में अदृश्य हैं" विशेष रूप से UNCHECEDED अपवाद पर लागू होता है। यह चेक किए गए अपवाद का पूरा बिंदु है ... ताकि आप जानते हैं कि कौन सा कोड क्या फेंकता है
न्यूटोपियन

2
@ ईवा वे समान नहीं हैं। एक गोटो स्टेटमेंट के साथ आप gotoकीवर्ड देख सकते हैं । एक लूप के साथ आप समापन ब्रेस breakया continueकीवर्ड देख सकते हैं । वे सभी वर्तमान विधि में एक बिंदु पर कूदते हैं। लेकिन आप हमेशा इसे नहीं देख सकते हैं throw, क्योंकि अक्सर यह वर्तमान पद्धति में नहीं होता है, लेकिन किसी अन्य विधि में जिसे यह कहता है (संभवतः अप्रत्यक्ष रूप से।)
finnw

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

2

अच्छा साबित होता है कि चेक किए गए अपवाद की आवश्यकता नहीं है:

  1. बहुत सारी रूपरेखा जो जावा के लिए कुछ काम करती है। वसंत की तरह जो अनियंत्रित अपवादों को जेडडीबीसी अपवाद को लपेटता है, लॉग को संदेश फेंक रहा है
  2. जावा के बाद आने वाली भाषाओं की बहुत, यहां तक ​​कि जावा प्लेटफॉर्म पर शीर्ष पर - वे उनका उपयोग नहीं करते हैं
  3. अपवादों की जांच की गई, यह एक तरह की भविष्यवाणी है कि ग्राहक उस कोड का उपयोग कैसे करेगा जो एक अपवाद को फेंकता है। लेकिन एक डेवलपर जो इस कोड को लिखता है वह कभी भी सिस्टम और व्यवसाय के बारे में नहीं जानता होगा कि कोड का क्लाइंट काम कर रहा है। एक उदाहरण के रूप में इंटरफेक विधि जो अपवाद को फेंकने के लिए मजबूर करती है। सिस्टम पर 100 कार्यान्वयन हैं, 50 या 90 में से भी कार्यान्वयन इस अपवाद को नहीं फेंकते हैं, लेकिन ग्राहक को अभी भी इस अपवाद को पकड़ना होगा यदि वह उस इंटरफ़ेस का संदर्भ देता है। वे 50 या 90 कार्यान्वयन उन अपवादों को खुद के अंदर संभालते हैं, जो अपवाद को छोड़ देते हैं (और यह उनके लिए अच्छा व्यवहार है)। हमें क्या करना चाहिए? मेरे पास कुछ बैकग्राउंड लॉजिक बेहतर होंगे जो लॉग को संदेश भेजकर सभी काम करेंगे। और यदि मैं, कोड के ग्राहक के रूप में, मुझे लगता है कि मुझे अपवाद को संभालने की आवश्यकता है - मैं इसे करूंगा।
  4. एक और उदाहरण जब मैं जावा में I / O के साथ काम कर रहा हूं, तो यह मुझे सभी अपवादों की जांच करने के लिए मजबूर करता है, अगर फ़ाइल मौजूद नहीं है? मुझे क्या करना चाहिए? यदि यह मौजूद नहीं है, तो सिस्टम अगले चरण पर नहीं जाएगा। इस पद्धति के ग्राहक को उस फ़ाइल से अपेक्षित सामग्री नहीं मिलेगी - वह रनटाइम अपवाद को संभाल सकता है, अन्यथा मुझे पहले चेक किए गए अपवाद की जांच करनी चाहिए, लॉग करने के लिए एक संदेश डालना चाहिए, फिर अपवाद को विधि के रूप में फेंक देना चाहिए। नहीं ... नहीं - मैं इसे RuntimeEception के साथ स्वचालित रूप से बेहतर करूंगा, जो इसे स्वचालित रूप से करता है। मैन्युअल रूप से इसे संभालने का कोई मतलब नहीं है - मुझे खुशी होगी कि मैंने लॉग में एक त्रुटि संदेश देखा (एओपी उस के साथ मदद कर सकता है .. कुछ जो जावा को ठीक करता है)। अगर, आखिरकार, मुझे लगता है कि सिस्टम को अंतिम उपयोगकर्ता को पॉप-अप संदेश दिखाना चाहिए - मैं इसे दिखाऊंगा, समस्या नहीं।

मैं खुश था अगर जावा मुझे पसंद का उपयोग करने के लिए प्रदान करेगा , जब मैं / ओ की तरह कोर लिबास के साथ काम कर रहा था। जैसे एक ही वर्ग की दो प्रतियाँ प्रदान करता है - एक रंटाइमसेप्शन के साथ लिपटा हुआ। तब हम तुलना कर सकते हैं कि लोग क्या उपयोग करेंगे । अभी के लिए, हालांकि, बहुत से लोग बेहतर रूप से जावा या अलग भाषा में शीर्ष पर कुछ रूपरेखा के लिए जाएंगे। स्काला की तरह, जुरी जो भी हो। कई लोग मानते हैं कि SUN सही था।


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

2

एक महत्वपूर्ण बात किसी ने भी उल्लेख नहीं किया है कि यह इंटरफेस और लैम्ब्डा अभिव्यक्ति के साथ कैसे हस्तक्षेप करता है।

मान लीजिए कि आप एक परिभाषित करते हैं MyAppException extends Exception। यह आपके आवेदन द्वारा फेंके गए सभी अपवादों द्वारा विरासत में मिला शीर्ष स्तर का अपवाद है। प्रत्येक विधि यह घोषित throws MyAppExceptionकरती है कि कौन सी बारीकियों में थोड़ा सा है, लेकिन प्रबंधनीय है। एक अपवाद हैंडलर अपवाद को लॉग करता है और उपयोगकर्ता को किसी तरह सूचित करता है।

सभी ठीक लग रहे हैं जब तक कि आप कुछ इंटरफ़ेस लागू नहीं करना चाहते हैं जो आपका नहीं है। जाहिर है कि यह फेंकने के इरादे की घोषणा नहीं करता है MyApException, इसलिए संकलक आपको अपवाद को वहां से फेंकने की अनुमति नहीं देता है।

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


1

हमने C # मुख्य वास्तुकार के कुछ संदर्भ देखे हैं।

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


2
जावा में चेक किए गए अपवादों के साथ समस्या एक गहरी समस्या से उपजी है, जो एक उदाहरण के गुणों के बजाय अपवाद के TYPE में बहुत अधिक जानकारी को समझाया गया है। चेक किए गए अपवादों को देखना उपयोगी होगा, यदि "चेक किया गया" साइटों को फेंकने / पकड़ने का एक गुण था, और अगर कोई घोषित रूप से निर्दिष्ट कर सकता है कि क्या एक चेक अपवाद जो कोड के ब्लॉक से बचता है, चेक किए गए अपवाद के रूप में रहना चाहिए, या देखा जाना चाहिए। अनियंत्रित अपवाद के रूप में किसी भी संलग्नक ब्लॉक द्वारा; इसी तरह कैच ब्लॉक्स यह निर्दिष्ट करने में सक्षम होना चाहिए कि वे केवल अपवाद की जाँच करना चाहते हैं।
सुपरकैट

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

0

मैंने अपवाद से निपटने के बारे में बहुत कुछ पढ़ा है, भले ही (अधिकांश समय) मैं वास्तव में यह नहीं कह सकता कि मैं जाँच किए गए अपवादों के अस्तित्व के बारे में खुश या दुखी हूं, यह मेरा लेना है: निम्न-स्तरीय कोड (IO, नेटवर्किंग) में अपवादों की जाँच की गई , OS, आदि) और उच्च-स्तरीय API / एप्लिकेशन स्तर में अनियंत्रित अपवाद।

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

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

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

सार्वजनिक शून्य रन () {

try {
     ... do something ...
} catch (Throwable throwable) {
     ApplicationContext.getExceptionService().handleException("Handle this exception", throwable);
}

}

यह आवश्यक नहीं है यदि आप जॉब (रन करने योग्य, कॉल करने योग्य, वर्कर) को शेड्यूल करने के लिए वर्कर सर्विस का उपयोग करते हैं, जो आपके लिए सब कुछ संभालती है।

बेशक यह सिर्फ मेरी राय है, और यह सही नहीं हो सकता है, लेकिन यह मेरे लिए एक अच्छा दृष्टिकोण है। मैं इस परियोजना को जारी करने के बाद देखूंगा कि क्या मुझे लगता है कि यह मेरे लिए अच्छा है, यह दूसरों के लिए भी अच्छा है ... :)

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