Java Language
अपवाद और अपवाद हैंडलिंग
खोज…
परिचय
Throwable
और उसके उपप्रकार की वस्तुओं को throw
कीवर्ड के साथ स्टैक ऊपर भेजा जा सकता है और try…catch
साथ पकड़ा जा सकता है try…catch
स्टेटमेंट try…catch
।
वाक्य - विन्यास
void someMethod () फेंकता है SomeException {} // पद्धति की घोषणा, फ़ोर्स विधि कॉलर्स को पकड़ने के लिए यदि SomeException एक जाँच अपवाद प्रकार है
प्रयत्न {
someMethod(); //code that might throw an exception
}
पकड़ (कुछ अपवाद ई) {
System.out.println("SomeException was thrown!"); //code that will run if certain exception (SomeException) is thrown
}
आखिरकार {
//code that will always run, whether try block finishes or not
}
कोशिश-कैच के साथ एक अपवाद को पकड़ने
एक अपवाद को पकड़ा जा सकता है और try...catch
का उपयोग करके पकड़ा जा सकता है। (वास्तव में, कोशिशें अन्य रूपों को लेने की try
करती हैं, जैसा कि try...catch...finally
बारे में अन्य उदाहरणों में वर्णित है try...catch...finally
और try-with-resources
।)
एक कैच ब्लॉक के साथ प्रयास करें
सबसे सरल रूप इस तरह दिखता है:
try {
doSomething();
} catch (SomeException e) {
handle(e);
}
// next statement
एक सरल try...catch
का व्यवहार try...catch
इस प्रकार है:
-
try
ब्लॉक में बयान निष्पादित किए जाते हैं। - कोई अपवाद नहीं में बयान से फेंक दिया जाता है, तो
try
ब्लॉक, तो नियंत्रण के बाद अगले बयान के गुजरताtry...catch
। - एक अपवाद के भीतर फेंक दिया जाता है, तो
try
ब्लॉक।- अपवाद ऑब्जेक्ट का परीक्षण यह देखने के लिए किया जाता है कि यह
SomeException
या उपप्रकार का एक उदाहरण है। - यदि यह है, तो
catch
ब्लॉक अपवाद को पकड़ लेगा:- चर
e
अपवाद वस्तु के लिए बाध्य है। -
catch
ब्लॉक के भीतर कोड निष्पादित किया जाता है। - यदि वह कोड एक अपवाद फेंकता है, तो मूल के स्थान पर नए फेंके गए अपवाद का प्रचार किया जाता है।
- अन्यथा, नियंत्रण
try...catch
बाद अगले बयान के लिए गुजरता हैtry...catch
।
- चर
- यदि ऐसा नहीं है, तो मूल अपवाद का प्रचार जारी है।
- अपवाद ऑब्जेक्ट का परीक्षण यह देखने के लिए किया जाता है कि यह
कई कैच के साथ प्रयास करें
एक try...catch
में कई catch
ब्लॉक भी हो सकते हैं। उदाहरण के लिए:
try {
doSomething();
} catch (SomeException e) {
handleOneWay(e)
} catch (SomeOtherException e) {
handleAnotherWay(e);
}
// next statement
यदि कई catch
ब्लॉक हैं, तो उन्हें पहले एक के साथ शुरू करने की कोशिश की जाती है, जब तक कि अपवाद के लिए एक मैच नहीं मिलता है। इसी हैंडलर को निष्पादित किया जाता है (ऊपर के रूप में), और फिर कंट्रोल को try...catch
स्टेटमेंट के बाद अगले स्टेटमेंट तक पहुंचाया जाता है। मैच के बाद catch
ब्लॉक हमेशा स्किप हो जाते हैं, भले ही हैंडलर कोड एक अपवाद फेंकता हो ।
"टॉप डाउन" मिलान की रणनीति में उन मामलों के परिणाम होते हैं जहां catch
ब्लॉक में अपवाद नहीं हैं। उदाहरण के लिए:
try {
throw new RuntimeException("test");
} catch (Exception e) {
System.out.println("Exception");
} catch (RuntimeException e) {
System.out.println("RuntimeException");
}
यह कोड स्निपेट "RuntimeException" के बजाय "अपवाद" का उत्पादन करेगा। चूंकि RuntimeException
की एक उप-प्रकार है Exception
, पहले (अधिक सामान्य) catch
मिलान किया जाएगा। दूसरा (अधिक विशिष्ट) catch
कभी भी निष्पादित नहीं किया जाएगा।
इससे सीखने का सबक यह है कि सबसे विशिष्ट catch
ब्लॉक (अपवाद प्रकारों के संदर्भ में) पहले प्रकट होने चाहिए, और सबसे सामान्य लोगों को अंतिम होना चाहिए। (कुछ जावा कंपाइलर आपको चेतावनी देंगे कि यदि किसी catch
को कभी अंजाम नहीं दिया जा सकता है, लेकिन यह एक संकलन त्रुटि नहीं है।)
बहु-अपवाद कैच ब्लॉक
जावा एसई 7 के साथ शुरू होने वाला, एक एकल catch
ब्लॉक असंबंधित अपवादों की एक सूची को संभाल सकता है। अपवाद प्रकार सूचीबद्ध हैं, एक ऊर्ध्वाधर बार ( |
) प्रतीक के साथ अलग। उदाहरण के लिए:
try {
doSomething();
} catch (SomeException | SomeOtherException e) {
handleSomeException(e);
}
बहु-अपवाद कैच का व्यवहार एकल-अपवाद मामले के लिए एक सरल विस्तार है। catch
मैच अपवादित मैचों में से एक (कम से कम) फेंके गए अपवादों से मेल खाता है।
विनिर्देश में कुछ अतिरिक्त सूक्ष्मता है। e
का प्रकार सूची में अपवाद प्रकारों का एक सिंथेटिक संघ है। जब e
के मूल्य का उपयोग किया जाता है, तो इसका स्थिर प्रकार यूनियन का सबसे कम सामान्य सुपरटेप है। हालांकि, यदि e
को catch
ब्लॉक के भीतर फिर से डाला जाता है, तो जो अपवाद प्रकार फेंके जाते हैं, वे यूनियन में टाइप होते हैं। उदाहरण के लिए:
public void method() throws IOException, SQLException
try {
doSomething();
} catch (IOException | SQLException e) {
report(e);
throw e;
}
उपरोक्त में, IOException
और SQLException
अपवादों की जाँच की जाती है, जिनका कम से कम सामान्य IOException
Exception
। इसका मतलब है कि report
विधि report(Exception)
मेल खाना चाहिए। हालांकि, संकलक जानता है कि फेंक केवल एक IOException
या एक SQLException
throw
सकता है। इस प्रकार, method
को throws IOException, SQLException
रूप में throws IOException, SQLException
बजाय throws Exception
। (जो एक अच्छी बात है: पिटफॉल देखना - थ्रोइंग, एक्ससेप्शन, एरर या रनटाइम एक्ससेप्शन ।)
अपवाद फेंकना
निम्नलिखित उदाहरण अपवाद फेंकने की मूल बातें दिखाता है:
public void checkNumber(int number) throws IllegalArgumentException {
if (number < 0) {
throw new IllegalArgumentException("Number must be positive: " + number);
}
}
अपवाद को 3 पंक्ति पर फेंक दिया गया है। इस कथन को दो भागों में विभाजित किया जा सकता है:
new IllegalArgumentException(...)
IllegalArgumentException
वर्ग का एक उदाहरण बना रहा है, जिसमें एक संदेश त्रुटि का वर्णन करता है जो अपवाद रिपोर्टिंग है।throw ...
तो अपवाद वस्तु फेंक रहा है।
जब अपवाद फेंक दिया जाता है, यह असामान्य रूप से समाप्त करने के लिए जब तक अपवाद नियंत्रित किया जाता है संलग्न बयान का कारण बनता है। यह अन्य उदाहरणों में वर्णित है।
उपरोक्त विवरण के अनुसार, एकल वस्तु को अपवाद वस्तु बनाना और फेंकना दोनों अच्छा है। समस्या के कारण को समझने में प्रोग्रामर की मदद करने के लिए अपवाद में एक सार्थक त्रुटि संदेश शामिल करना भी अच्छा अभ्यास है। हालांकि, यह जरूरी नहीं है कि संदेश आपको अंतिम उपयोगकर्ता को दिखाना चाहिए। (शुरुआत के लिए, जावा के पास अपवाद संदेशों का अंतर्राष्ट्रीयकरण करने के लिए कोई प्रत्यक्ष समर्थन नहीं है।)
कुछ और बिंदु बनाने हैं:
हमने
checkNumber
कोthrows IllegalArgumentException
घोषित किया है। यह कड़ाई से आवश्यक नहीं था, क्योंकिIllegalArgumentException
एक जाँच अपवाद है; जावा एक्सेप्शन पदानुक्रम देखें - अनियंत्रित और जाँच अपवाद । हालाँकि, ऐसा करने के लिए यह अच्छा अभ्यास है, और अपवादों को शामिल करने के लिए एक विधि की javadoc टिप्पणियां भी शामिल हैं।throw
बयान के तुरंत बाद कोड पहुंच से बाहर है । इसलिए अगर हमने यह लिखा है:throw new IllegalArgumentException("it is bad"); return;
संकलक
return
स्टेटमेंट के लिए एक संकलन त्रुटि की रिपोर्ट करेगा।
अपवाद जंजीर
कई मानक अपवाद एक दूसरे के साथ एक निर्माता है cause
पारंपरिक के अलावा तर्क message
तर्क। cause
आपको अपवादों को श्रृंखलाबद्ध करने की अनुमति देता है। यहाँ एक उदाहरण है।
पहले हम एक अनियंत्रित अपवाद को परिभाषित करते हैं कि हमारा एप्लिकेशन तब फेंक रहा है जब वह एक गैर-वसूली योग्य त्रुटि का सामना करता है। ध्यान दें कि हमने एक कंस्ट्रक्टर को शामिल किया है जो cause
तर्क को स्वीकार करता है।
public class AppErrorException extends RuntimeException {
public AppErrorException() {
super();
}
public AppErrorException(String message) {
super(message);
}
public AppErrorException(String message, Throwable cause) {
super(message, cause);
}
}
इसके बाद, यहां कुछ कोड है जो अपवाद जंजीरों को दिखाता है।
public String readFirstLine(String file) throws AppErrorException {
try (Reader r = new BufferedReader(new FileReader(file))) {
String line = r.readLine();
if (line != null) {
return line;
} else {
throw new AppErrorException("File is empty: " + file);
}
} catch (IOException ex) {
throw new AppErrorException("Cannot read file: " + file, ex);
}
}
try
ब्लॉक के भीतर throw
एक समस्या का पता लगाता है और एक साधारण संदेश के साथ एक अपवाद के माध्यम से रिपोर्ट करता है। इसके विपरीत, catch
ब्लॉक में throw
IOException
को एक नए (चेक किए गए) अपवाद में लपेटकर संभाल रहा है। हालांकि, यह मूल अपवाद को दूर नहीं फेंक रहा है। cause
रूप में IOException
को पारित करके, हम इसे रिकॉर्ड करते हैं ताकि इसे स्टैकट्रेस में मुद्रित किया जा सके, जैसा कि स्टैकट्रैक्स बनाने और पढ़ने में समझाया गया है।
कस्टम अपवाद
अधिकांश परिस्थितियों में, अपवादों को फेंकते समय मौजूदा जेनेरिक Exception
वर्गों का उपयोग करना कोड-डिज़ाइन के दृष्टिकोण से सरल होता है। यह विशेष रूप से सच है अगर आपको केवल एक साधारण त्रुटि संदेश ले जाने के लिए अपवाद की आवश्यकता है। उस मामले में, RuntimeException आमतौर पर पसंद की जाती है, क्योंकि यह एक जाँच अपवाद नहीं है। अन्य अपवाद कक्षाएं त्रुटियों के सामान्य वर्गों के लिए मौजूद हैं:
- UnsupportedOperationException - एक निश्चित ऑपरेशन समर्थित नहीं है
- IllegalArgumentException - एक अमान्य पैरामीटर मान एक विधि को पारित किया गया था
- IllegalStateException - आपका API आंतरिक रूप से एक ऐसी स्थिति में पहुंच गया है जो कभी नहीं होना चाहिए, या जो आपके एपीआई का अमान्य तरीके से उपयोग करने के परिणामस्वरूप होता है।
ऐसे मामले जहां आप एक कस्टम अपवाद वर्ग का उपयोग करना चाहते हैं, उनमें निम्नलिखित शामिल हैं:
- आप दूसरों द्वारा उपयोग के लिए एक एपीआई या पुस्तकालय लिख रहे हैं, और आप अपने एपीआई के उपयोगकर्ताओं को विशेष रूप से अपने एपीआई से अपवादों को पकड़ने और संभालने में सक्षम होने की अनुमति देना चाहते हैं, और उन अपवादों को अन्य, अधिक सामान्य अपवादों से अलग करने में सक्षम होना चाहते हैं ।
- आप अपने प्रोग्राम के एक हिस्से में एक विशिष्ट प्रकार की त्रुटि के लिए अपवाद फेंक रहे हैं, जिसे आप अपने प्रोग्राम के किसी अन्य भाग में पकड़ना और संभालना चाहते हैं, और आप इन त्रुटियों को अन्य, अधिक सामान्य त्रुटियों से अलग करने में सक्षम होना चाहते हैं।
आप किसी अनियंत्रित अपवाद के लिए RuntimeException
विस्तार करके अपने स्वयं के कस्टम अपवाद बना सकते हैं, या किसी Exception
को बढ़ाकर अपवाद की जाँच कर सकते हैं जो RuntimeException के उपवर्ग नहीं है , क्योंकि:
अपवाद के उपवर्ग जो कि RuntimeException के उपवर्ग भी नहीं हैं अपवादों की जाँच की जाती है
public class StringTooLongException extends RuntimeException {
// Exceptions can have methods and fields like other classes
// those can be useful to communicate information to pieces of code catching
// such an exception
public final String value;
public final int maximumLength;
public StringTooLongException(String value, int maximumLength){
super(String.format("String exceeds maximum Length of %s: %s", maximumLength, value));
this.value = value;
this.maximumLength = maximumLength;
}
}
जिनका उपयोग पूर्वनिर्धारित अपवादों के रूप में किया जा सकता है:
void validateString(String value){
if (value.length() > 30){
throw new StringTooLongException(value, 30);
}
}
और उन क्षेत्रों का उपयोग किया जा सकता है जहां अपवाद पकड़ा और संभाला जाता है:
void anotherMethod(String value){
try {
validateString(value);
} catch(StringTooLongException e){
System.out.println("The string '" + e.value +
"' was longer than the max of " + e.maximumLength );
}
}
ओरेकल के जावा डॉक्यूमेंटेशन के अनुसार, ध्यान रखें:
[...] यदि किसी ग्राहक से यथोचित रूप से एक अपवाद से उबरने की अपेक्षा की जा सकती है, तो उसे एक अपवाद बना दें। यदि कोई ग्राहक अपवाद से उबरने के लिए कुछ नहीं कर सकता है, तो इसे अनियंत्रित अपवाद बनाएं।
अधिक:
संसाधनों के साथ प्रयास करें
जैसा कि ट्राइ-कैच-फाइनल स्टेटमेंट उदाहरण दिखाता है, finally
क्लॉज का उपयोग करते हुए संसाधन सफाई को किनारे के मामलों को सही ढंग से लागू करने के लिए "बॉयलर-प्लेट" कोड की एक महत्वपूर्ण राशि की आवश्यकता होती है। Java 7 इस समस्या से निपटने के लिए बहुत सरल तरीका प्रदान करता है, जैसे कि try-with-resource स्टेटमेंट के रूप में।
एक संसाधन क्या है?
जावा 7 ने java.lang.AutoCloseable
इंटरफ़ेस की शुरुआत की, ताकि कोशिश-संसाधनों के विवरण का उपयोग करके कक्षाओं को प्रबंधित किया जा सके। AutoCloseable
को लागू करने वाली कक्षाओं के उदाहरणों को संसाधनों के रूप में संदर्भित किया जाता है । आम तौर पर इनका निपटान करने के लिए कचरा कलेक्टर पर निर्भर होने के बजाय समय पर फैशन का निपटान करने की आवश्यकता होती है।
AutoCloseable
इंटरफ़ेस एक एकल विधि को परिभाषित करता है:
public void close() throws Exception
एक close()
विधि को उचित तरीके से संसाधन का निपटान करना चाहिए। विनिर्देश में कहा गया है कि पहले से ही निपट चुके संसाधन पर विधि को कॉल करना सुरक्षित होना चाहिए। इसके अलावा, कक्षाओं कि लागू Autocloseable
दृढ़ता से घोषित करने के लिए प्रोत्साहित किया जाता है close()
की तुलना में एक अधिक विशिष्ट अपवाद फेंकने के लिए विधि Exception
, या बिल्कुल भी कोई अपवाद नहीं।
मानक जावा कक्षाओं और इंटरफेस की एक विस्तृत श्रृंखला AutoCloseable
लागू करती है। इसमें शामिल है:
-
InputStream
,OutputStream
और उनके उपवर्ग -
Reader
,Writer
और उनके उपवर्ग -
Socket
औरServerSocket
और उनके उपवर्ग -
Channel
और उसके उपवर्ग, और - JDBC
Connection
,Statement
औरResultSet
और उनके उपवर्गों को इंटरफेस करता है।
आवेदन और तीसरे पक्ष के वर्ग भी ऐसा कर सकते हैं।
मूल प्रयास-संसाधन विवरण के साथ
एक कोशिश के साथ संसाधनों का सिंटैक्स शास्त्रीय ट्राइ-कैच , ट्राइ- एंड और ट्राइ-कैच-आखिर रूपों पर आधारित है। यहाँ एक "बुनियादी" रूप का एक उदाहरण है; यानी बिना catch
के फॉर्म या finally
।
try (PrintStream stream = new PrintStream("hello.txt")) {
stream.println("Hello world!");
}
प्रयास किए जाने वाले संसाधनों को try
खंड के बाद (...)
अनुभाग में चर के रूप में घोषित किया जाता है। ऊपर दिए गए उदाहरण में, हम एक संसाधन चर stream
घोषणा करते हैं और इसे एक नए बनाए गए PrintStream
से आरंभ करते हैं।
संसाधन चर आरंभ होने के बाद, try
ब्लॉक निष्पादित किया जाता है। जब वह पूरा हो जाता है, तो यह सुनिश्चित करने के लिए कि संसाधन लीक नहीं करता है, stream.close()
को स्वचालित रूप से कहा जाएगा। ध्यान दें कि close()
कॉल कुछ भी नहीं होता है कि ब्लॉक कैसे पूरा होता है।
एन्हांस्ड प्रयास-के साथ-संसाधन विवरण
प्री-जावा 7 ट्राइ-कैच-आखिर सिंटैक्स के साथ, ट्राइ-एंड -रिसोर्स स्टेटमेंट को catch
और finally
ब्लॉक के साथ बढ़ाया जा सकता है। निम्न कोड स्निपेट FileNotFoundException
से निपटने के लिए हमारे पिछले एक catch
ब्लॉक को FileNotFoundException
है जिसे PrintStream
कंस्ट्रक्टर फेंक सकता है:
try (PrintStream stream = new PrintStream("hello.txt")) {
stream.println("Hello world!");
} catch (FileNotFoundException ex) {
System.err.println("Cannot open the file");
} finally {
System.err.println("All done");
}
यदि या तो संसाधन आरंभीकरण या कोशिश ब्लॉक अपवाद फेंकता है, तो catch
ब्लॉक निष्पादित किया जाएगा। finally
ब्लॉक को हमेशा निष्पादित किया जाएगा, जैसा कि पारंपरिक ट्राइ-कैच-एंड स्टेटमेंट के साथ होता है।
यद्यपि ध्यान देने योग्य कुछ बातें हैं:
- संसाधन चर
catch
औरfinally
ब्लॉक में दायरे से बाहर है । - रिसोर्स क्लीनअप
catch
ब्लॉक से मिलान करने के स्टेटमेंट से पहले होगा। - यदि स्वचालित संसाधन क्लीनअप ने अपवाद को फेंक दिया, तो वह
catch
ब्लॉक में से एक में पकड़ा जा सकता है।
कई संसाधनों का प्रबंधन
ऊपर दिए गए कोड स्निपेट एक एकल संसाधन को प्रबंधित करते हुए दिखाते हैं। वास्तव में, try-with-resource एक कथन में कई संसाधनों का प्रबंधन कर सकता है। उदाहरण के लिए:
try (InputStream is = new FileInputStream(file1);
OutputStream os = new FileOutputStream(file2)) {
// Copy 'is' to 'os'
}
यह वैसा ही व्यवहार करता है जैसा आप अपेक्षा करते हैं। दोनों is
और os
के अंत में अपने आप बंद कर रहे हैं try
ब्लॉक। नोट करने के लिए कुछ बिंदु हैं:
- इनिशियलाइज़ेशन कोड क्रम में होते हैं, और बाद में रिसोर्स वैरिएबल इनिशियलाइज़र पहले वाले के मानों का उपयोग कर सकते हैं।
- सफलतापूर्वक शुरू किए गए सभी संसाधन चर साफ किए जाएंगे।
- संसाधन चर उनकी घोषणाओं के उल्टे क्रम में साफ किए जाते हैं।
इस प्रकार, ऊपर के उदाहरण में, is
से पहले आरंभ नहीं हो जाता os
और यह के बाद साफ है, और is
साफ हो जाएगा अगर वहाँ जबकि आरंभ एक अपवाद है os
।
प्रयास-के साथ-साथ संसाधन और शास्त्रीय कोशिश-कैच-आखिर
जावा लैंग्वेज स्पेसिफिकेशन, क्लासिकल ट्राइ-कैच-एंड स्टेटमेंट के संदर्भ में कोशिश-के-संसाधन रूपों के व्यवहार को निर्दिष्ट करता है। (कृपया पूर्ण विवरण के लिए जेएलएस देखें।)
उदाहरण के लिए, यह बुनियादी कोशिश-के साथ संसाधन :
try (PrintStream stream = new PrintStream("hello.txt")) {
stream.println("Hello world!");
}
इस कोशिश-कैच के बराबर परिभाषित किया गया है:
// Note that the constructor is not part of the try-catch statement
PrintStream stream = new PrintStream("hello.txt");
// This variable is used to keep track of the primary exception thrown
// in the try statement. If an exception is thrown in the try block,
// any exception thrown by AutoCloseable.close() will be suppressed.
Throwable primaryException = null;
// The actual try block
try {
stream.println("Hello world!");
} catch (Throwable t) {
// If an exception is thrown, remember it for the finally block
primaryException = t;
throw t;
} finally {
if (primaryException == null) {
// If no exception was thrown so far, exceptions thrown in close() will
// not be caught and therefore be passed on to the enclosing code.
stream.close();
} else {
// If an exception has already been thrown, any exception thrown in
// close() will be suppressed as it is likely to be related to the
// previous exception. The suppressed exception can be retrieved
// using primaryException.getSuppressed().
try {
stream.close();
} catch (Throwable suppressedException) {
primaryException.addSuppressed(suppressedException);
}
}
}
(जेएलएस निर्दिष्ट करता है कि वास्तविक t
और primaryException
वेरिएबल सामान्य जावा कोड के लिए अदृश्य होंगे।)
कोशिश-के साथ संसाधनों का बढ़ाया रूप मूल रूप के साथ एक तुल्यता के रूप में निर्दिष्ट किया गया है। उदाहरण के लिए:
try (PrintStream stream = new PrintStream(fileName)) {
stream.println("Hello world!");
} catch (NullPointerException ex) {
System.err.println("Null filename");
} finally {
System.err.println("All done");
}
के बराबर है:
try {
try (PrintStream stream = new PrintStream(fileName)) {
stream.println("Hello world!");
}
} catch (NullPointerException ex) {
System.err.println("Null filename");
} finally {
System.err.println("All done");
}
स्टैकट्रैक बनाना और पढ़ना
जब एक अपवाद ऑब्जेक्ट बनाया जाता है (यानी जब आप इसे new
करते हैं), Throwable
कंस्ट्रक्टर उस संदर्भ के बारे में जानकारी कैप्चर करता है जिसमें अपवाद बनाया गया था। बाद में, यह जानकारी स्टैकट्रेस के रूप में आउटपुट हो सकती है, जिसका उपयोग उस समस्या का निदान करने में मदद करने के लिए किया जा सकता है जो पहले स्थान पर अपवाद का कारण बना।
एक स्टैच्यूटर प्रिंट करना
स्टैकट्रेस प्रिंट करना केवल printStackTrace()
पद्धति को कॉल करने का मामला है। उदाहरण के लिए:
try {
int a = 0;
int b = 0;
int c = a / b;
} catch (ArithmeticException ex) {
// This prints the stacktrace to standard output
ex.printStackTrace();
}
दलील के बिना printStackTrace()
विधि एप्लिकेशन के मानक आउटपुट पर प्रिंट होगी; यानी वर्तमान System.out
। printStackTrace(PrintStream)
और printStackTrace(PrintWriter)
ओवरलोड भी हैं जो एक निर्दिष्ट Stream
या Writer
प्रिंट होते हैं।
टिप्पणियाँ:
स्टैकट्रेस में अपवाद का विवरण शामिल नहीं है। आप उन विवरणों को प्राप्त करने के लिए
toString()
पद्धति का उपयोग कर सकते हैं; जैसे// Print exception and stacktrace System.out.println(ex); ex.printStackTrace();
स्टैकट्रेस प्रिंटिंग को संयम से इस्तेमाल किया जाना चाहिए; देखें नुकसान - अत्यधिक या अनुचित स्टैकट्रैक्स । लॉगिंग फ़्रेमवर्क का उपयोग करना बेहतर है, और लॉग किए जाने वाले अपवाद ऑब्जेक्ट को पास करें।
एक स्टैकट्रेस को समझना
दो फ़ाइलों में दो वर्गों से मिलकर निम्नलिखित सरल कार्यक्रम पर विचार करें। (हमने चित्रण प्रयोजनों के लिए फ़ाइल नाम और जोड़े गए लाइन नंबर दिखाए हैं।)
File: "Main.java"
1 public class Main {
2 public static void main(String[] args) {
3 new Test().foo();
4 }
5 }
File: "Test.java"
1 class Test {
2 public void foo() {
3 bar();
4 }
5
6 public int bar() {
7 int a = 1;
8 int b = 0;
9 return a / b;
10 }
जब इन फ़ाइलों को संकलित किया जाता है और चलाया जाता है, तो हम निम्नलिखित आउटपुट प्राप्त करेंगे।
Exception in thread "main" java.lang.ArithmeticException: / by zero
at Test.bar(Test.java:9)
at Test.foo(Test.java:3)
at Main.main(Main.java:3)
हमें यह बताने के लिए एक समय में एक पंक्ति पढ़ें कि यह हमें क्या बता रहा है।
लाइन # 1 हमें बताता है कि "मुख्य" नामक धागे को एक अनकहा अपवाद के कारण समाप्त कर दिया गया है। अपवाद का पूरा नाम java.lang.ArithmeticException
, और अपवाद संदेश "/ बाय जीरो" है।
यदि हम इस अपवाद के लिए javadocs देखें, तो यह कहता है:
जब एक असाधारण अंकगणित की स्थिति उत्पन्न हुई है तो फेंको। उदाहरण के लिए, एक पूर्णांक "शून्य से विभाजित" इस वर्ग का एक उदाहरण फेंकता है।
दरअसल, "/ बाय जीरो" संदेश एक मजबूत संकेत है कि अपवाद का कारण यह है कि कुछ कोड ने शून्य से कुछ को विभाजित करने का प्रयास किया है। पर क्या?
शेष 3 पंक्तियाँ स्टैक ट्रेस हैं। प्रत्येक पंक्ति कॉल स्टैक पर एक विधि (या कंस्ट्रक्टर) कॉल का प्रतिनिधित्व करती है, और हर एक हमें तीन चीजें बताता है:
- वर्ग और विधि का नाम जिसे निष्पादित किया जा रहा था,
- स्रोत कोड फ़ाइल नाम,
- जिस स्टेटमेंट को निष्पादित किया जा रहा था, उसका सोर्स कोड नंबर
स्टैकट्रेस की इन पंक्तियों को शीर्ष पर वर्तमान कॉल के लिए फ्रेम के साथ सूचीबद्ध किया गया है। ऊपर हमारे उदाहरण में शीर्ष फ़्रेम Test.bar
विधि में है, और Test.java फ़ाइल की पंक्ति 9 पर है। वह निम्न पंक्ति है:
return a / b;
अगर हम फ़ाइल में पहले कुछ पंक्तियों को देखते हैं जहाँ b
को इनिशियलाइज़ किया गया है, तो यह स्पष्ट है कि b
का मान शून्य होगा। हम बिना किसी संदेह के कह सकते हैं कि यह अपवाद का कारण है।
अगर हमें और आगे जाने की जरूरत है, तो हम स्टैकट्रेस से देख सकते हैं कि bar()
को foo()
से टेस्ट.जाव की लाइन 3 पर बुलाया गया था, और उस foo()
को Main.main()
से बुलाया गया था।
नोट: स्टैक फ्रेम में वर्ग और विधि के नाम कक्षाओं और विधियों के आंतरिक नाम हैं। आपको निम्नलिखित असामान्य मामलों को पहचानने की आवश्यकता होगी:
- एक नेस्टेड या आंतरिक वर्ग "आउटरक्लास $ इनरक्लास" जैसा दिखेगा।
- एक अनाम आंतरिक वर्ग "OuterClass $ 1", "OuterClass $ 2", वगैरह की तरह दिखेगा।
- जब एक कंस्ट्रक्टर में कोड, उदाहरण के क्षेत्र आरंभीकरण या एक उदाहरण इनिशियलाइज़र ब्लॉक निष्पादित किया जा रहा है, तो विधि का नाम "" होगा।
- जब एक स्थिर क्षेत्र इनिशियलाइज़र या स्थिर इनिशियलाइज़र ब्लॉक में कोड निष्पादित किया जा रहा है, तो विधि का नाम "" होगा।
(जावा के कुछ संस्करणों में, स्टैक्ट्रेस फॉर्मेटिंग कोड बार-बार स्टैकफ्रेम अनुक्रमों का पता लगाता है और अलग-अलग होता है, जैसा कि तब हो सकता है जब अत्यधिक पुनरावृत्ति के कारण कोई एप्लिकेशन विफल हो जाता है।)
अपवाद चैनिंग और नेस्टेड स्टैकट्रैक्स
अपवाद की चेनिंग तब होती है जब कोड का एक टुकड़ा एक अपवाद को पकड़ता है, और फिर एक नया बनाता है और फेंकता है, पहला अपवाद कारण के रूप में गुजरता है। यहाँ एक उदाहरण है:
File: Test,java
1 public class Test {
2 int foo() {
3 return 0 / 0;
4 }
5
6 public Test() {
7 try {
8 foo();
9 } catch (ArithmeticException ex) {
10 throw new RuntimeException("A bad thing happened", ex);
11 }
12 }
13
14 public static void main(String[] args) {
15 new Test();
16 }
17 }
जब उपरोक्त वर्ग संकलित और चलाया जाता है, तो हमें निम्नलिखित स्टैकट्रेस मिलता है:
Exception in thread "main" java.lang.RuntimeException: A bad thing happened
at Test.<init>(Test.java:10)
at Test.main(Test.java:15)
Caused by: java.lang.ArithmeticException: / by zero
at Test.foo(Test.java:3)
at Test.<init>(Test.java:8)
... 1 more
स्टैकट्रेस अपवाद के लिए वर्ग नाम, विधि और कॉल स्टैक से शुरू होता है जो (इस मामले में) के कारण एप्लिकेशन क्रैश हो जाता है। इसके बाद "कारण माना जाता है": रेखा जो cause
अपवाद की रिपोर्ट करती है। वर्ग के नाम और संदेश को सूचित किया जाता है, इसके बाद अपवाद के स्टैक फ़्रेम होते हैं। ट्रेस एक "... एन अधिक" के साथ समाप्त होता है जो इंगित करता है कि पिछले एन फ्रेम पिछले अपवाद के समान हैं।
"इसके कारण:" केवल आउटपुट में शामिल होता है जब प्राथमिक अपवाद का cause
null
नहीं cause
है)। अपवाद अनिश्चित काल तक जंजीर हो सकते हैं, और उस स्थिति में स्टैकट्रेस के कई कारण हो सकते हैं: "निशान।"
नोट: cause
तंत्र केवल जावा 1.4.0 में Throwable
एपीआई में उजागर किया गया था। इससे पहले, कारण का प्रतिनिधित्व करने के लिए एक कस्टम अपवाद फ़ील्ड का उपयोग करके एप्लिकेशन द्वारा कार्यान्वित किए जाने वाले अपवाद printStackTrace
की आवश्यकता होती है, और एक कस्टम printStackTrace
विधि।
स्ट्रिंग के रूप में स्टैकट्रेस कैप्चर करना
कभी-कभी, एक एप्लिकेशन को जावा String
रूप में स्टैकट्रेस को पकड़ने में सक्षम होने की आवश्यकता होती है, ताकि इसका उपयोग अन्य उद्देश्यों के लिए किया जा सके। ऐसा करने के लिए सामान्य दृष्टिकोण अस्थायी OutputStream
या Writer
बनाना है जो इन-मेमोरी बफर को लिखता है और printStackTrace(...)
को पास करता है।
अपाचे कॉमन्स और अमरुद लाइब्रेरी एक स्ट्रींग के रूप में स्टैकट्रेस कैप्चर करने के लिए उपयोगिता विधियाँ प्रदान करते हैं:
org.apache.commons.lang.exception.ExceptionUtils.getStackTrace(Throwable)
com.google.common.base.Throwables.getStackTraceAsString(Throwable)
यदि आप अपने कोड बेस में थर्ड पार्टी लाइब्रेरी का उपयोग नहीं कर सकते हैं, तो निम्न कार्य के साथ निम्न विधि करें:
/**
* Returns the string representation of the stack trace.
*
* @param throwable the throwable
* @return the string.
*/
public static String stackTraceToString(Throwable throwable) {
StringWriter stringWriter = new StringWriter();
throwable.printStackTrace(new PrintWriter(stringWriter));
return stringWriter.toString();
}
ध्यान दें कि यदि आपका इरादा स्टैकट्रेस का विश्लेषण करना है, तो स्टैकट्रेस को पार्स करने का प्रयास करने के लिए getStackTrace()
और getCause()
का उपयोग करना अधिक सरल है।
बाधा डालना
InterruptedException
एक भ्रमित करने वाला जानवर है - यह Thread.sleep()
जैसे प्रतीत होता है अहानिकर तरीकों से पता चलता है, लेकिन इसे गलत तरीके से संभालने से हार्ड-टू- Thread.sleep()
कोड होता है जो समवर्ती वातावरण में खराब व्यवहार करता है।
अपने सबसे बुनियादी में, अगर एक InterruptedException
पकड़ा जाता है, तो इसका मतलब है कि कोई व्यक्ति, कहीं न कहीं, थ्रेड. Thread.interrupt()
नाम से आपके कोड में वर्तमान में चल रहा है। आप यह कहना चाह सकते हैं कि "यह मेरा कोड है! मैं इसे कभी बाधित नहीं करूंगा!" " और इसलिए कुछ ऐसा करें:
// Bad. Don't do this.
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// disregard
}
लेकिन यह एक "असंभव" घटना को संभालने का गलत तरीका है। यदि आप जानते हैं कि आपका आवेदन कभी भी InterruptedException
नहीं होगा, तो आपको इस तरह की घटना को अपने कार्यक्रम की मान्यताओं के गंभीर उल्लंघन के रूप में InterruptedException
चाहिए और जितनी जल्दी हो सके बाहर निकल जाना चाहिए।
"असंभव" रुकावट को संभालने का उचित तरीका ऐसा है:
// When nothing will interrupt your code
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new AssertionError(e);
}
यह दो काम करता है; यह पहली बार थ्रेड की रुकावट की स्थिति को पुनर्स्थापित करता है (जैसे कि InterruptedException
को पहले स्थान पर नहीं फेंका गया था), और फिर यह एक AssertionError
देता है, जिससे आपके आवेदन के मूल आवेगों का उल्लंघन होने का संकेत मिलता है। यदि आप कुछ के लिए जानते हैं कि आप इस थ्रेड को कभी बाधित नहीं करेंगे तो यह कोड रन सुरक्षित है क्योंकि catch
ब्लॉक तक कभी नहीं पहुंचना चाहिए।
अमरूद के Uninterruptibles
वर्ग का उपयोग इस पैटर्न को सरल बनाने में मदद करता है; Uninterruptibles.sleepUninterruptibly()
कॉलिंग एक थ्रेड की बाधित स्थिति को रोकता है जब तक कि नींद की अवधि समाप्त नहीं हो जाती है (जिस बिंदु पर इसे बाद में कॉल के लिए बहाल किया जाता है, निरीक्षण करने और अपने स्वयं के InterruptedException
करने के लिए कॉल करें)। यदि आप जानते हैं कि आप इस तरह के कोड को कभी बाधित नहीं करेंगे, तो यह सुरक्षित रूप से आपके नींद की कॉल को एक कोशिश-ब्लॉक में लपेटने से बचता है।
अधिक बार, हालांकि, आप गारंटी नहीं दे सकते कि आपका धागा कभी बाधित नहीं होगा। विशेष रूप से यदि आप ऐसा कोड लिख रहे हैं जो किसी Executor
या किसी अन्य थ्रेड-मैनेजमेंट द्वारा निष्पादित किया जाएगा, तो यह महत्वपूर्ण है कि आपका कोड तुरंत हस्तक्षेप करने के लिए प्रतिक्रिया देता है, अन्यथा आपका एप्लिकेशन स्टाल या गतिरोध भी होगा।
ऐसे मामलों में सबसे अच्छी बात यह है कि InterruptedException
को कॉल स्टैक को फैलाने की अनुमति देने के लिए, प्रत्येक विधि में एक throws InterruptedException
को जोड़ते हुए। यह कठिन लग सकता है, लेकिन यह वास्तव में एक वांछनीय संपत्ति है - आपके विधि के हस्ताक्षर अब कॉल करने वालों को इंगित करते हैं कि यह तुरंत बाधित होने पर प्रतिक्रिया देगा।
// Let the caller determine how to handle the interrupt if you're unsure
public void myLongRunningMethod() throws InterruptedException {
...
}
सीमित मामलों में (उदाहरण के लिए एक विधि को ओवरराइड करते समय, जो किसी भी चेक किए गए अपवादों को नहीं throw
है) आप बिना किसी अपवाद को उठाए बाधा स्थिति को रीसेट कर सकते हैं, उम्मीद करते हैं कि बाधा को संभालने के लिए जो भी कोड निष्पादित किया गया है। यह व्यवधान को संभालने में देरी करता है, लेकिन इसे पूरी तरह से दबा नहीं पाता है।
// Suppresses the exception but resets the interrupted state letting later code
// detect the interrupt and handle it properly.
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return ...; // your expectations are still broken at this point - try not to do more work.
}
जावा अपवाद पदानुक्रम - अनियंत्रित और जाँच अपवाद
सभी जावा अपवाद अपवाद श्रेणी पदानुक्रम में कक्षाओं के उदाहरण हैं। इसे निम्नानुसार दर्शाया जा सकता है:
-
java.lang.Throwable
- यह सभी अपवाद वर्गों के लिए आधार वर्ग है। इसके तरीके और निर्माता सभी अपवादों के लिए सामान्य कार्यक्षमता की एक सीमा को लागू करते हैं।-
java.lang.Exception
- यह सभी सामान्य अपवादों का सुपरक्लास है।- विभिन्न मानक और कस्टम अपवाद कक्षाएं।
-
java.lang.RuntimeException
- यह सभी सामान्य अपवादों का सुपरक्लास है जो अनियंत्रित अपवाद हैं ।- विभिन्न मानक और कस्टम रनटाइम अपवाद कक्षाएं।
-
java.lang.Error
- यह सभी "घातक त्रुटि" अपवादों का सुपरक्लास है।
-
टिप्पणियाँ:
- जाँच और अनियंत्रित अपवादों के बीच का अंतर नीचे वर्णित है।
-
Throwable
,Exception
औरRuntimeException
वर्ग के रूप में व्यवहार किया जाना चाहिएabstract
; देखें नुकसान - फेंकने योग्य, अपवाद, त्रुटि या रनटाइम अपवाद । -
Error
अपवाद JVM द्वारा उन स्थितियों में फेंका जाता है जहां यह किसी एप्लिकेशन को पुनर्प्राप्त करने का प्रयास करने के लिए असुरक्षित या नासमझी होगी। -
Throwable
कस्टम उपप्रकार घोषित करना नासमझी होगी। जावा उपकरण और पुस्तकालय यह मान सकते हैं किError
औरException
Throwable
के केवल प्रत्यक्ष उपप्रकार हैं, और यदि गलत है तो गलत है।
जाँच बनाम अनियोजित अपवाद
कुछ प्रोग्रामिंग भाषाओं में अपवाद समर्थन की आलोचनाओं में से एक यह जानना मुश्किल है कि किसी दिए गए तरीके या प्रक्रिया के अपवाद कौन से फेंक सकते हैं। यह देखते हुए कि एक अनहेल्दी अपवाद प्रोग्राम को क्रैश करने के लिए उत्तरदायी है, यह अपवादों को नाजुकता का स्रोत बना सकता है।
जावा भाषा चेक किए गए अपवाद तंत्र के साथ इस चिंता को संबोधित करती है। सबसे पहले, जावा अपवादों को दो श्रेणियों में वर्गीकृत करता है:
चेक किए गए अपवाद आमतौर पर प्रत्याशित घटनाओं का प्रतिनिधित्व करते हैं जो एक आवेदन से निपटने में सक्षम होना चाहिए। उदाहरण के लिए,
IOException
और इसके उपप्रकार त्रुटि स्थितियों का प्रतिनिधित्व करते हैं जो I / O संचालन में हो सकते हैं। उदाहरणों में शामिल हैं, फ़ाइल विफल होना क्योंकि फ़ाइल या निर्देशिका मौजूद नहीं है, नेटवर्क पढ़ना और लिखना विफल रहता है क्योंकि नेटवर्क कनेक्शन टूट गया है और इसी तरह।अनियंत्रित अपवाद आमतौर पर अप्रत्याशित घटनाओं का प्रतिनिधित्व करते हैं जो एक आवेदन से निपट नहीं सकते हैं। ये आमतौर पर एप्लिकेशन में बग का परिणाम होते हैं।
(निम्नलिखित में, "फेंका गया" स्पष्ट रूप से फेंके गए किसी भी अपवाद ( throw
स्टेटमेंट द्वारा) को संदर्भित करता है, या अव्यवस्थित रूप से (एक विफल डेरेक्शन में, टाइप कास्ट और इतने पर)। इसी तरह, "प्रचारित" एक अपवाद को संदर्भित करता है जिसे एक में फेंक दिया गया था। नेस्टेड कॉल, और उस कॉल के भीतर नहीं पकड़ा गया है। नीचे नमूना कोड यह स्पष्ट करेगा।)
जाँच किए गए अपवाद तंत्र का दूसरा भाग यह है कि उन तरीकों पर प्रतिबंध है जहाँ जाँच अपवाद हो सकती है:
- जब एक जाँच अपवाद को फेंक दिया जाता है या एक विधि में प्रचारित किया जाता है, तो इसे या तो विधि द्वारा पकड़ा जाना चाहिए , या विधि के
throws
क्लॉज़ में सूचीबद्ध किया जाना चाहिए । (throws
क्लॉज का महत्व इस उदाहरण में वर्णित है।) - जब एक चेक किए गए अपवाद को इनिशियलाइज़र ब्लॉक में फेंक दिया जाता है या प्रचारित किया जाता है, तो उसे ब्लॉक को पकड़ा जाना चाहिए।
- फ़ील्ड इनिशियलाइज़ेशन एक्सप्रेशन में मेथड कॉल को एक विधि कॉल द्वारा प्रचारित नहीं किया जा सकता है। (इस तरह के अपवाद को पकड़ने का कोई तरीका नहीं है।)
संक्षेप में, एक जाँच अपवाद को या तो संभाला जाना चाहिए, या घोषित किया जाना चाहिए।
ये प्रतिबंध अनियंत्रित अपवादों पर लागू नहीं होते हैं। इसमें उन सभी मामलों को शामिल किया गया है, जहां एक अपवाद को स्पष्ट रूप से फेंक दिया गया है, क्योंकि ऐसे सभी मामले अनियंत्रित अपवादों को फेंक देते हैं।
अपवाद उदाहरणों की जाँच की
ये कोड स्निपेट चेक किए गए अपवाद प्रतिबंधों को स्पष्ट करने के लिए हैं। प्रत्येक मामले में, हम एक संकलन त्रुटि के साथ कोड का एक संस्करण दिखाते हैं, और त्रुटि को ठीक करने वाला दूसरा संस्करण।
// This declares a custom checked exception.
public class MyException extends Exception {
// constructors omitted.
}
// This declares a custom unchecked exception.
public class MyException2 extends RuntimeException {
// constructors omitted.
}
पहला उदाहरण दिखाता है कि स्पष्ट रूप से जाँच किए गए अपवादों को "फेंक" के रूप में घोषित किया जा सकता है यदि उन्हें विधि में संभाला नहीं जाना चाहिए।
// INCORRECT
public void methodThrowingCheckedException(boolean flag) {
int i = 1 / 0; // Compiles OK, throws ArithmeticException
if (flag) {
throw new MyException(); // Compilation error
} else {
throw new MyException2(); // Compiles OK
}
}
// CORRECTED
public void methodThrowingCheckedException(boolean flag) throws MyException {
int i = 1 / 0; // Compiles OK, throws ArithmeticException
if (flag) {
throw new MyException(); // Compilation error
} else {
throw new MyException2(); // Compiles OK
}
}
दूसरा उदाहरण दिखाता है कि एक प्रचारित चेक अपवाद से कैसे निपटा जा सकता है।
// INCORRECT
public void methodWithPropagatedCheckedException() {
InputStream is = new FileInputStream("someFile.txt"); // Compilation error
// FileInputStream throws IOException or a subclass if the file cannot
// be opened. IOException is a checked exception.
...
}
// CORRECTED (Version A)
public void methodWithPropagatedCheckedException() throws IOException {
InputStream is = new FileInputStream("someFile.txt");
...
}
// CORRECTED (Version B)
public void methodWithPropagatedCheckedException() {
try {
InputStream is = new FileInputStream("someFile.txt");
...
} catch (IOException ex) {
System.out.println("Cannot open file: " + ex.getMessage());
}
}
अंतिम उदाहरण से पता चलता है कि स्थिर क्षेत्र इनिशियलाइज़र में चेक किए गए अपवाद से कैसे निपटना है।
// INCORRECT
public class Test {
private static final InputStream is =
new FileInputStream("someFile.txt"); // Compilation error
}
// CORRECTED
public class Test {
private static final InputStream is;
static {
InputStream tmp = null;
try {
tmp = new FileInputStream("someFile.txt");
} catch (IOException ex) {
System.out.println("Cannot open file: " + ex.getMessage());
}
is = tmp;
}
}
नोट यह पिछले मामले में, हम भी समस्याओं से निपटने के लिए है कि is
करने के लिए एक बार से अधिक नहीं सौंपा जा सकता है, और अभी तक भी, को सौंपा जा करने के लिए भी एक अपवाद के मामले में है।
परिचय
अपवाद वे त्रुटियां हैं जो किसी प्रोग्राम को निष्पादित करते समय होती हैं। नीचे जावा प्रोग्राम पर विचार करें जो दो पूर्णांकों को विभाजित करता है।
class Division {
public static void main(String[] args) {
int a, b, result;
Scanner input = new Scanner(System.in);
System.out.println("Input two integers");
a = input.nextInt();
b = input.nextInt();
result = a / b;
System.out.println("Result = " + result);
}
}
अब हम उपरोक्त कोड को संकलित करते हैं और निष्पादित करते हैं, और शून्य से प्रयास विभाजन के लिए आउटपुट देखते हैं:
Input two integers
7 0
Exception in thread "main" java.lang.ArithmeticException: / by zero
at Division.main(Disivion.java:14)
शून्य द्वारा विभाजन एक अमान्य ऑपरेशन है जो एक मान उत्पन्न करेगा जिसे पूर्णांक के रूप में प्रस्तुत नहीं किया जा सकता है। जावा एक अपवाद फेंककर इससे संबंधित है । इस स्थिति में, अपवाद ArithmeticException class का एक उदाहरण है।
नोट: स्टैक निशान बनाने और पढ़ने पर उदाहरण बताता है कि दो संख्याओं के बाद आउटपुट का क्या मतलब है।
एक अपवाद की उपयोगिता प्रवाह नियंत्रण है जो इसे अनुमति देता है। अपवादों का उपयोग किए बिना, इस समस्या का एक विशिष्ट समाधान पहले जाँच कर सकता है यदि b == 0
:
class Division {
public static void main(String[] args) {
int a, b, result;
Scanner input = new Scanner(System.in);
System.out.println("Input two integers");
a = input.nextInt();
b = input.nextInt();
if (b == 0) {
System.out.println("You cannot divide by zero.");
return;
}
result = a / b;
System.out.println("Result = " + result);
}
}
यह संदेश प्रिंट करता है जिसे You cannot divide by zero.
जब उपयोगकर्ता शून्य से विभाजित करने का प्रयास करता है, तो कंसोल को एक शानदार तरीके से प्रोग्राम को शांत और क्विट करता है। अपवाद संचालन के माध्यम से इस समस्या से निपटने का एक बराबर तरीका बदलने के लिए होगा if
एक साथ प्रवाह नियंत्रण try-catch
ब्लॉक:
...
a = input.nextInt();
b = input.nextInt();
try {
result = a / b;
}
catch (ArithmeticException e) {
System.out.println("An ArithmeticException occurred. Perhaps you tried to divide by zero.");
return;
}
...
एक कोशिश पकड़ ब्लॉक इस प्रकार निष्पादित किया जाता है:
-
try
ब्लॉक में कोड निष्पादित करना शुरूtry
। - यदि प्रयास ब्लॉक में कोई अपवाद होता है, तो तुरंत निरस्त करें और यह देखने के लिए जांचें कि क्या यह अपवाद
catch
ब्लॉक द्वारा पकड़ा गया है (इस मामले में, जब अपवादArithmeticException
का एक उदाहरण है)। - यदि अपवाद पकड़ा गया है , तो इसे चर
e
को सौंपा गया है औरcatch
ब्लॉक निष्पादित किया गया है। - यदि या तो
try
याcatch
ब्लॉक पूरा हो गया है (यानी कोड निष्पादन के दौरान कोई भी अपवाद नहीं हुआ है) तोtry-catch
ब्लॉक के नीचे कोड निष्पादित करना जारी रखें।
यह आमतौर पर एक अनुप्रयोग के सामान्य प्रवाह नियंत्रण के भाग के रूप में अपवाद हैंडलिंग का उपयोग करने के लिए अच्छा अभ्यास माना जाता है जहां व्यवहार अन्यथा अपरिभाषित या अप्रत्याशित होगा। उदाहरण के लिए, बजाय लौटने की null
जब एक विधि विफल रहता है, यह इतना है कि विधि का आवेदन करने से उपयोग स्थिति अपवाद तरह का रख-रखाव के माध्यम से ऊपर सचित्र के लिए अपने स्वयं के प्रवाह नियंत्रण परिभाषित कर सकते हैं एक अपवाद फेंकने के लिए आम तौर पर बेहतर अभ्यास है। कुछ अर्थों में, यह एक विशेष प्रकार को वापस करने की समस्या के आसपास हो जाता है, क्योंकि विशिष्ट समस्या को इंगित करने के लिए कई प्रकार के अपवादों में से किसी एक को फेंक दिया जा सकता है।
अपवाद का उपयोग कैसे करें और कैसे न करें, इस बारे में अधिक सलाह के लिए, जावा नुकसान - अपवाद का उपयोग करें
स्टेटमेंट कैच ब्लॉक में रिटर्न स्टेटमेंट्स
हालांकि यह बुरा अभ्यास है, एक अपवाद हैंडलिंग ब्लॉक में कई रिटर्न स्टेटमेंट जोड़ना संभव है:
public static int returnTest(int number){
try{
if(number%2 == 0) throw new Exception("Exception thrown");
else return x;
}
catch(Exception e){
return 3;
}
finally{
return 7;
}
}
यह विधि हमेशा 7 वापस आएगी क्योंकि कोशिश / कैच ब्लॉक से जुड़े अंत में कुछ भी वापस करने से पहले निष्पादित किया जाता है। अब, जैसा कि अंत में return 7;
, यह मान ट्राई / कैच रिटर्न वैल्यूज को बढ़ाता है।
यदि कैच ब्लॉक एक आदिम मान लौटाता है और उस प्राइमरी वैल्यू को बाद में अंततः ब्लॉक में बदल दिया जाता है, तो कैच ब्लॉक में दिया गया मान वापस आ जाएगा और अंत में ब्लॉक से आए बदलावों को नजरअंदाज कर दिया जाएगा।
नीचे दिया गया उदाहरण "0" प्रिंट करेगा, न कि "1"।
public class FinallyExample {
public static void main(String[] args) {
int n = returnTest(4);
System.out.println(n);
}
public static int returnTest(int number) {
int returnNumber = 0;
try {
if (number % 2 == 0)
throw new Exception("Exception thrown");
else
return returnNumber;
} catch (Exception e) {
return returnNumber;
} finally {
returnNumber = 1;
}
}
}
अपवादों की उन्नत सुविधाएँ
यह उदाहरण अपवादों के लिए कुछ उन्नत सुविधाओं और उपयोग-मामलों को शामिल करता है।
प्रोग्रामस्टैक को कॉलस्टैक की जांच करना
अपवाद स्टैकट्रैक्स का प्राथमिक उपयोग एक एप्लिकेशन त्रुटि और उसके संदर्भ के बारे में जानकारी प्रदान करना है ताकि प्रोग्रामर समस्या का निदान और ठीक कर सके। कभी-कभी इसका उपयोग अन्य चीजों के लिए किया जा सकता है। उदाहरण के लिए, एक SecurityManager
वर्ग को कॉल स्टैक की जांच करने की आवश्यकता हो सकती है कि क्या कॉल करने वाले कोड पर भरोसा किया जाना चाहिए।
आप कॉल स्टैक की जांच करने के लिए अपवादों का उपयोग इस प्रकार कर सकते हैं:
Exception ex = new Exception(); // this captures the call stack
StackTraceElement[] frames = ex.getStackTrace();
System.out.println("This method is " + frames[0].getMethodName());
System.out.println("Called from method " + frames[1].getMethodName());
इस पर कुछ महत्वपूर्ण चेतावनी हैं:
StackTraceElement
में उपलब्ध जानकारी सीमित है।printStackTrace
द्वारा प्रदर्शित की गई कोई और जानकारी उपलब्ध नहीं है। (फ्रेम में स्थानीय चर के मान उपलब्ध नहीं हैं।)getStackTrace()
लिए javadocsgetStackTrace()
कि JVM को फ्रेम छोड़ने की अनुमति है:कुछ आभासी मशीनें, कुछ परिस्थितियों में, स्टैक ट्रेस से एक या अधिक स्टैक फ़्रेम को छोड़ सकती हैं। चरम मामले में, एक आभासी मशीन जिसमें इस थकाऊ के बारे में कोई स्टैक ट्रेस जानकारी नहीं है, इस विधि से शून्य-लंबाई सरणी वापस करने की अनुमति है।
अपवाद निर्माण का अनुकूलन
जैसा कि कहीं और उल्लेख किया गया है, एक अपवाद का निर्माण करना महंगा है क्योंकि यह वर्तमान थ्रेड पर सभी स्टैक फ़्रेमों के बारे में जानकारी कैप्चर करने और रिकॉर्ड करने पर जोर देता है। कभी-कभी, हम जानते हैं कि जानकारी किसी दिए गए अपवाद के लिए उपयोग नहीं होने जा रही है; उदाहरण के लिए स्टैकट्रेस को कभी भी प्रिंट नहीं किया जाएगा। उस स्थिति में, एक कार्यान्वयन ट्रिक है जिसे हम कस्टम अपवाद में उपयोग कर सकते हैं ताकि जानकारी पर कब्जा न हो सके।
स्टैकट्रैक के लिए आवश्यक स्टैक फ्रेम जानकारी को तब कैप्चर किया जाता है, जब Throwable
कंस्ट्रक्टर Throwable.fillInStackTrace()
विधि को कॉल करते हैं। यह विधि public
, जिसका अर्थ है कि एक उपवर्ग इसे ओवरराइड कर सकता है। चाल एक के साथ Throwable
से विरासत में मिली विधि को ओवरराइड करना है जो कुछ भी नहीं करता है; जैसे
public class MyException extends Exception {
// constructors
@Override
public void fillInStackTrace() {
// do nothing
}
}
इस दृष्टिकोण के साथ समस्या यह है कि एक अपवाद जो fillInStackTrace()
को ओवरराइड fillInStackTrace()
, स्टैकट्रेस को कभी नहीं पकड़ सकता है, और उन परिदृश्यों में बेकार है जहां आपको एक की आवश्यकता होती है।
ढेर लगाना या बदलना
कुछ स्थितियों में, सामान्य तरीके से बनाए गए अपवाद के लिए स्टैकट्रेस में या तो गलत जानकारी होती है, या ऐसी जानकारी जो डेवलपर उपयोगकर्ता को प्रकट नहीं करना चाहता है। इन परिदृश्यों के लिए, Throwable.setStackTrace
का उपयोग जानकारी रखने वाली StackTraceElement
ऑब्जेक्ट की सरणी को बदलने के लिए किया जा सकता है।
उदाहरण के लिए, निम्न का उपयोग अपवाद की स्टैक जानकारी को छोड़ने के लिए किया जा सकता है:
exception.setStackTrace(new StackTraceElement[0]);
दमन अपवाद
जावा 7 ने प्रयास-के साथ-साथ संसाधनों का निर्माण, और अपवाद दमन की संबद्ध अवधारणा पेश की। निम्नलिखित स्निपेट पर विचार करें:
try (Writer w = new BufferedWriter(new FileWriter(someFilename))) {
// do stuff
int temp = 0 / 0; // throws an ArithmeticException
}
जब अपवाद को फेंक दिया जाता है, तो try
उस w
पर close()
कॉल करेगी जो किसी भी बफर आउटपुट को फ्लश करेगा और फिर FileWriter
बंद कर देगा। लेकिन क्या होता है अगर आउटपुट को फ्लश करते समय एक IOException
को फेंक दिया जाता है?
क्या होता है कि किसी संसाधन की सफाई करते समय फेंके गए अपवाद को दबा दिया जाता है । अपवाद पकड़ा गया है, और प्राथमिक अपवाद की दबी अपवाद सूची में जोड़ा गया है। अगले संसाधनों के साथ- साथ अन्य संसाधनों की सफाई जारी रहेगी। अंत में, प्राथमिक अपवाद को फिर से उखाड़ फेंका जाएगा।
एक समान पैटर्न तब होता है जब यह संसाधन इनिशियलाइज़ेशन के दौरान फेंका गया एक अपवाद होता है, या यदि try
ब्लॉक सामान्य रूप से पूरा होता है। फेंका गया पहला अपवाद प्राथमिक अपवाद बन जाता है, और बाद में सफाई से उत्पन्न होने वाले को दबा दिया जाता है।
दबा अपवाद अपवाद getSuppressedExceptions
को कॉल करके प्राथमिक अपवाद ऑब्जेक्ट से प्राप्त किया जा सकता है।
कोशिश-आखिर और कोशिश-आखिर-बयान
try...catch...finally
स्टेटमेंट क्लीन-अप कोड के साथ अपवाद हैंडलिंग को जोड़ती है। finally
ब्लॉक में कोड होता है जिसे सभी परिस्थितियों में निष्पादित किया जाएगा। यह उन्हें संसाधन प्रबंधन, और अन्य प्रकार के सफाई के लिए उपयुक्त बनाता है।
प्रयास करें-अंत में
यहाँ सरल का एक उदाहरण है ( try...finally
) फ़ॉर्म:
try {
doSomething();
} finally {
cleanUp();
}
try...finally
का व्यवहार try...finally
में इस प्रकार है:
-
try
ब्लॉक में कोड निष्पादित किया गया है। - यदि कोई अपवाद नहीं किया गया था तो
try
ब्लॉक में:-
finally
ब्लॉक में कोड निष्पादित किया जाता है। - यदि
finally
एक अपवाद फेंकता है, तो वह अपवाद प्रचारित होता है। - अन्यथा, नियंत्रण
try...finally
बाद अगले कथन पर जाता हैtry...finally
।
-
- यदि कोई अपवाद आज़माने वाले ब्लॉक में डाला गया था:
-
finally
ब्लॉक में कोड निष्पादित किया जाता है। - यदि
finally
एक अपवाद फेंकता है, तो वह अपवाद प्रचारित होता है। - अन्यथा, मूल अपवाद का प्रचार जारी है।
-
finally
ब्लॉक के भीतर कोड हमेशा निष्पादित किया जाएगा। (केवल अपवाद हैं अगर System.exit(int)
कहा जाता है, या यदि JVM पैनिक।) इस प्रकार एक finally
ब्लॉक सही स्थान कोड है जिसे हमेशा निष्पादित करने की आवश्यकता होती है; उदाहरण के लिए फाइलें और अन्य संसाधन बंद करना या ताले जारी करना।
कोशिश पकड़ने के अंत में
हमारा दूसरा उदाहरण दिखाता है कि कैसे catch
और finally
एक साथ उपयोग किया जा सकता है। यह भी दिखाता है कि संसाधनों की सफाई सीधी नहीं है।
// This code snippet writes the first line of a file to a string
String result = null;
Reader reader = null;
try {
reader = new BufferedReader(new FileReader(fileName));
result = reader.readLine();
} catch (IOException ex) {
Logger.getLogger.warn("Unexpected IO error", ex); // logging the exception
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException ex) {
// ignore / discard this exception
}
}
}
(काल्पनिक) कोशिशों का पूरा सेट try...catch...finally
में इस उदाहरण में यहाँ वर्णन करने के लिए बहुत जटिल हैं। सरल संस्करण यह है कि finally
ब्लॉक में कोड हमेशा निष्पादित किया जाएगा।
संसाधन प्रबंधन के दृष्टिकोण से इसे देखते हुए:
- हम
try
ब्लॉक से पहले "संसाधन" (यानीreader
चर) घोषित करते हैं ताकि यहfinally
ब्लॉक के लिए गुंजाइश में हो। -
new FileReader(...)
IOError
, फ़ाइल को खोलने परcatch
किसी भीIOError
अपवाद को संभालने में सक्षम है। - हमें
finally
ब्लॉक में एकreader.close()
की आवश्यकता है क्योंकि कुछ अपवाद पथ हैं जिन्हें हम या तोtry
ब्लॉक में याcatch
ब्लॉक में रोक नहीं सकते हैं। - हालांकि, बाद से एक अपवाद से पहले हो सकता है फेंका गया है
reader
प्रारंभ किया गया था, हम भी एक स्पष्ट की जरूरत हैnull
परीक्षण। - अंत में,
reader.close()
कॉल (काल्पनिक रूप से) एक अपवाद फेंक सकता है। हम इस बारे में परवाह नहीं करते हैं, लेकिन यदि हम स्रोत पर अपवाद को नहीं पकड़ते हैं, तो हमें कॉल स्टैक के साथ इससे निपटने की आवश्यकता होगी।
जावा 7 और बाद में एक वैकल्पिक कोशिश के साथ संसाधन सिंटैक्स प्रदान करते हैं जो संसाधन सफाई को काफी सरल करता है।
एक विधि घोषणा में 'फेंकता' खंड
जावा के चेक किए गए अपवाद तंत्र को प्रोग्रामर को यह घोषित करने की आवश्यकता होती है कि कुछ तरीके चेक किए गए अपवादों को फेंक सकते हैं। यह throws
क्लॉज का उपयोग करके किया जाता है। उदाहरण के लिए:
public class OddNumberException extends Exception { // a checked exception
}
public void checkEven(int number) throws OddNumberException {
if (number % 2 != 0) {
throw new OddNumberException();
}
}
throws OddNumberException
घोषणा करता है कि के लिए एक कॉल checkEven
एक अपवाद प्रकार का है कि फेंक सकता है OddNumberException
।
एक throws
क्लॉज प्रकारों की एक सूची घोषित कर सकता है, और अनियंत्रित अपवादों के साथ-साथ जाँच किए गए अपवादों को भी शामिल कर सकता है।
public void checkEven(Double number)
throws OddNumberException, ArithmeticException {
if (!Double.isFinite(number)) {
throw new ArithmeticException("INF or NaN");
} else if (number % 2 != 0) {
throw new OddNumberException();
}
}
अनियंत्रित अपवादों को फेंकने की घोषणा करने का क्या मतलब है?
एक विधि घोषणा में throws
खंड दो उद्देश्यों में कार्य करता है:
यह संकलक को बताता है कि किन अपवादों को फेंका गया है ताकि संकलक त्रुटियों के रूप में अप्रकाशित (चेक किए गए) अपवादों को रिपोर्ट कर सके।
यह एक प्रोग्रामर को बताता है जो कोड लिख रहा है जो उस विधि को कॉल करता है जो उम्मीद करने के लिए अपवाद है। इस उद्देश्य के लिए, यह अक्सर
throws
सूची में अनियंत्रित अपवादों को शामिल करने के लिए इंद्रियों को बनाता है।
नोट: कि throws
लिस्ट का उपयोग javadoc टूल द्वारा एपीआई डॉक्यूमेंट बनाते समय भी किया जाता है, और एक विशिष्ट IDE के "होवर टेक्स्ट" विधि युक्तियों के द्वारा।
फेंकता है और ओवरराइड करने की विधि
throws
क्लॉज विधि के ओवरड्राइडिंग के उद्देश्य के लिए एक विधि के हस्ताक्षर का हिस्सा बनता है। एक ओवरराइड विधि को चेक किए गए अपवादों के एक ही सेट के साथ ओवरराइड विधि द्वारा फेंका जा सकता है, या एक सबसेट के साथ घोषित किया जा सकता है। हालाँकि ओवरराइड विधि अतिरिक्त जाँच अपवाद नहीं जोड़ सकती। उदाहरण के लिए:
@Override
public void checkEven(int number) throws NullPointerException // OK—NullPointerException is an unchecked exception
...
@Override
public void checkEven(Double number) throws OddNumberException // OK—identical to the superclass
...
class PrimeNumberException extends OddNumberException {}
class NonEvenNumberException extends OddNumberException {}
@Override
public void checkEven(int number) throws PrimeNumberException, NonEvenNumberException // OK—these are both subclasses
@Override
public void checkEven(Double number) throws IOExcepion // ERROR
इस नियम का कारण यह है कि अगर एक ओवरराइड विधि एक जाँच अपवाद को फेंक सकती है जो ओवरराइड विधि नहीं फेंक सकती है, तो यह प्रकार की प्रतिस्थापन क्षमता को तोड़ देगा।