जावा स्थैतिक आरंभीकरण खंड से जाँच अपवाद को फेंकने की अनुमति क्यों नहीं देता है? इस डिजाइन निर्णय के पीछे क्या कारण था?
जावा स्थैतिक आरंभीकरण खंड से जाँच अपवाद को फेंकने की अनुमति क्यों नहीं देता है? इस डिजाइन निर्णय के पीछे क्या कारण था?
जवाबों:
क्योंकि आपके स्रोत में इन चेक किए गए अपवादों को संभालना संभव नहीं है। आरंभीकरण प्रक्रिया पर आपका कोई नियंत्रण नहीं है और स्थैतिक {} ब्लॉक को आपके स्रोत से नहीं बुलाया जा सकता है ताकि आप उन्हें ट्राइ-कैच से घेर सकें।
चूँकि आप चेक किए गए अपवाद द्वारा बताई गई किसी भी त्रुटि को संभाल नहीं सकते हैं, इसलिए यह जाँच की गई कि अपवाद स्थैतिक ब्लॉक को फेंकना अस्वीकार कर दिया जाए।
स्टैटिक ब्लॉक को चेक किए गए अपवादों को नहीं फेंकना चाहिए, लेकिन फिर भी अनियंत्रित / रनटाइम-अपवादों को फेंकने की अनुमति देता है। लेकिन उपरोक्त कारणों के अनुसार आप इन्हें संभाल नहीं पाएंगे।
संक्षेप में, यह प्रतिबंध डेवलपर को कुछ बनाने से रोकता है (या कम से कम इसके लिए कठिन बनाता है) जिसके परिणामस्वरूप ऐसी त्रुटियां हो सकती हैं जिनसे आवेदन पुनर्प्राप्त करने में असमर्थ होगा।
static { if(1 < 10) { throw new NullPointerException(); } }
आप किसी भी चेक किए गए अपवाद को पकड़कर और इसे अनियंत्रित अपवाद मानकर समस्या पर काम कर सकते हैं। यह अनियंत्रित अपवाद वर्ग एक आवरण के रूप में अच्छी तरह से काम करता है java.lang.ExceptionInInitializerError
:।
नमूना कोड:
protected static class _YieldCurveConfigHelperSingleton {
public static YieldCurveConfigHelper _staticInstance;
static {
try {
_staticInstance = new YieldCurveConfigHelper();
}
catch (IOException | SAXException | JAXBException e) {
throw new ExceptionInInitializerError(e);
}
}
}
catch (Exception e) {
इसके बजाय कोशिश करें ।
System.exit(...)
(या समतुल्य) आपका एकमात्र विकल्प है,
इसे इस तरह देखना होगा (यह वैध जावा कोड नहीं है)
// Not a valid Java Code
static throws SomeCheckedException {
throw new SomeCheckedException();
}
लेकिन आप इसे कैसे पकड़ेंगे? चेक किए गए अपवादों को पकड़ने की आवश्यकता है। कुछ उदाहरणों की कल्पना करें जो वर्ग को आरंभीकृत कर सकते हैं (या हो सकता है क्योंकि यह पहले से ही आरंभीकृत है), और बस उस की जटिलता का ध्यान आकर्षित करने के लिए, जो मैं पेश करता हूं, मैंने उदाहरणों को एक और स्थिर initalizer में रखा:
static {
try {
ClassA a = new ClassA();
Class<ClassB> clazz = Class.forName(ClassB.class);
String something = ClassC.SOME_STATIC_FIELD;
} catch (Exception oops) {
// anybody knows which type might occur?
}
}
और एक और गंदी बात -
interface MyInterface {
final static ClassA a = new ClassA();
}
कल्पना कीजिए कि क्लासए के पास एक स्टैटिक इनिशियलाइज़र था, जो एक अपवाद को फेंक रहा था: इस मामले में MyInterface (जो कि 'हिडन' स्टैटिक इनिशियलाइज़र वाला इंटरफ़ेस है) को अपवाद को फेंकना होगा या उसे संभालना होगा - एक इंटरफ़ेस पर अपवाद को हैंडल करना? बेहतर है कि इसे वैसे ही छोड़ दें।
main
जाँच अपवाद छोड़ सकते हैं। जाहिर है कि उन्हें संभाला नहीं जा सकता।
main()
स्टैक ट्रेस के साथ अपवाद को प्रिंट करता है System.err
, फिर कॉल करता है System.exit()
। अंत में, इस सवाल का जवाब शायद है: "क्योंकि जावा डिजाइनरों ने ऐसा कहा था"।
जावा स्थैतिक आरंभीकरण खंड से जाँच अपवाद को फेंकने की अनुमति क्यों नहीं देता है?
तकनीकी रूप से, आप ऐसा कर सकते हैं। हालांकि, चेक किए गए अपवाद को ब्लॉक के भीतर पकड़ा जाना चाहिए। ब्लॉक के बाहर प्रचारित अपवाद की अनुमति नहीं है ।
तकनीकी रूप से, एक स्थिर इनिशियलाइज़र ब्लॉक 1 से बाहर प्रचारित करने के लिए अनियंत्रित अपवाद की अनुमति देना भी संभव है । लेकिन जानबूझकर ऐसा करना बहुत बुरा विचार है! समस्या यह है कि जेवीएम स्वयं अनियंत्रित अपवाद को पकड़ता है, और इसे लपेटता है और इसे ए के रूप में पुनर्व्यवस्थित करता है ExceptionInInitializerError
।
NB: Error
यह एक नियमित अपवाद नहीं है। आपको इससे उबरने का प्रयास नहीं करना चाहिए।
ज्यादातर मामलों में, अपवाद नहीं पकड़ा जा सकता है:
public class Test {
static {
int i = 1;
if (i == 1) {
throw new RuntimeException("Bang!");
}
}
public static void main(String[] args) {
try {
// stuff
} catch (Throwable ex) {
// This won't be executed.
System.out.println("Caught " + ex);
}
}
}
$ java Test
Exception in thread "main" java.lang.ExceptionInInitializerError
Caused by: java.lang.RuntimeException: Bang!
at Test.<clinit>(Test.java:5)
कहीं नहीं है आप 2try ... catch
को पकड़ने के लिए ऊपर में रख सकते हैं ।ExceptionInInitializerError
कुछ मामलों में आप इसे पकड़ सकते हैं। उदाहरण के लिए, यदि आपने कॉल करके क्लास इनिशियलाइज़ेशन को ट्रिगर किया है, तो आप Class.forName(...)
कॉल को एक या एक या बाद में try
पकड़ सकते हैं ।ExceptionInInitializerError
NoClassDefFoundError
हालांकि, यदि आप एक से पुनर्प्राप्त करने का प्रयास करते हैं तो आप ExceptionInInitializerError
एक सड़क पर चलने के लिए उत्तरदायी हैं। समस्या यह है कि त्रुटि को फेंकने से पहले, जेवीएम उस वर्ग को चिह्नित करता है जिससे समस्या "विफल" हुई। आप बस इसका उपयोग नहीं कर पाएंगे। इसके अलावा, कोई भी अन्य वर्ग जो असफल वर्ग पर निर्भर करते हैं, यदि वे आरंभ करने का प्रयास करते हैं, तो वे असफल स्थिति में चले जाएंगे। आगे बढ़ने का एकमात्र तरीका सभी असफल वर्गों को उतारना है। यह गतिशील रूप से लोड कोड 3 के लिए संभव हो सकता है , लेकिन सामान्य तौर पर यह नहीं है।
1 - यह एक संकलित त्रुटि है अगर एक स्थिर ब्लॉक बिना शर्त अनियंत्रित अपवाद को फेंकता है।
2 - आप एक डिफ़ॉल्ट अनकैप्ड अपवाद हैंडलर को पंजीकृत करके इसे बाधित करने में सक्षम हो सकते हैं, लेकिन यह आपको ठीक करने की अनुमति नहीं देगा, क्योंकि आपका "मुख्य" धागा शुरू नहीं हो सकता है।
3 - यदि आप असफल कक्षाओं को पुनर्प्राप्त करना चाहते हैं, तो आपको उन लोडर से छुटकारा पाने की आवश्यकता होगी जो उन्हें लोड करते हैं।
इस डिजाइन निर्णय के पीछे क्या कारण था?
यह प्रोग्रामर को उस कोड को लिखने से बचाने के लिए है जो अपवादों को फेंकता है जिन्हें संभाला नहीं जा सकता है!
जैसा कि हमने देखा है, एक स्टेटिक इनिशियलाइज़र में एक अपवाद एक विशिष्ट एप्लिकेशन को एक ईंट में बदल देता है। सबसे अच्छी बात यह है कि भाषा डिजाइनर एक संकलित त्रुटि के रूप में चेक किए गए मामले से निपटने के लिए कर सकते हैं। (दुर्भाग्य से, अनियंत्रित अपवादों के लिए भी ऐसा करना व्यावहारिक नहीं है।)
ठीक है, तो आपको क्या करना चाहिए अगर आपके कोड को "" की जरूरत है "एक स्थिर इनिशियलाइज़र में अपवादों को फेंकने के लिए। असल में, दो विकल्प हैं:
यदि (पूर्ण!) ब्लॉक के भीतर अपवाद से वसूली संभव है, तो ऐसा करें।
अन्यथा, अपने कोड का पुनर्गठन करें ताकि आरंभिक स्थैतिक आरंभीकरण खंड (या स्थैतिक चर के आरंभक) में न हो।
जावा लैंग्वेज स्पेसिफिकेशन्स पर एक नज़र डालें : यह कहा गया है कि यह एक संकलित समय त्रुटि है यदि स्थिर इनिशियलाइज़र विफल रहता है, तो एक चेक किए गए अपवाद के साथ अचानक पूरा करने में सक्षम है।
public class Main { static { try{Class.forName("whathappenswhenastaticblockthrowsanexception");} catch (ClassNotFoundException e){throw new RuntimeException(e);} } public static void main(String[] args){} }
आउटपुट:Exception in thread "main" java.lang.ExceptionInInitializerError Caused by: java.lang.RuntimeException: java.lang.ClassNotFoundException: whathappenswhenastaticblockthrowsanexception at Main.<clinit>(Main.java:6) Caused by: java.lang.ClassNotFoundException: whathappen...
चूंकि आपके द्वारा लिखा गया कोई भी कोड स्टेटिक इनिशियलाइज़ेशन ब्लॉक नहीं कह सकता है, इसलिए चेक को फेंकना उपयोगी नहीं है exceptions
। यदि यह संभव था, जब जाँच किए गए अपवादों को फेंक दिया जाता है तो jvm क्या करेगा? Runtimeexceptions
प्रचारित हैं।
उदाहरण के लिए: स्प्रिंग का डिस्पैचरसर्वलेट (org.springframework.web.servlet.DispatcherServlet) उस परिदृश्य को संभालता है जो एक चेक अपवाद को पकड़ता है और दूसरा अनियंत्रित अपवाद को फेंकता है।
static {
// Load default strategy implementations from properties file.
// This is currently strictly internal and not meant to be customized
// by application developers.
try {
ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
}
catch (IOException ex) {
throw new IllegalStateException("Could not load '" + DEFAULT_STRATEGIES_PATH + "': " + ex.getMessage());
}
मैं एक जाँच अपवाद भी फेंकने में सक्षम हूँ ...।
static {
try {
throw new IOException();
} catch (Exception e) {
// Do Something
}
}