2012-11-23 11 views
10

जब मैं एक उदाहरण के प्रारंभ (नहीं वर्ग आरंभीकरण) ब्लॉक में एक अपवाद फेंक करने की कोशिश मैं त्रुटि मिलती है:जावा इंस्टेंस प्रारंभिक ब्लॉक में अपवाद फेंकने की अनुमति क्यों नहीं है?

initializer must be able to complete normally 

क्यों यह अनुमति नहीं है, हालांकि जावा वह खुद करता है?

निम्नलिखित उदाहरण चार कक्षाएं बनाता है। कक्षा A एक अंकगणितीय अपवाद के कारण तत्काल के दौरान विफल रहता है। यह catch के साथ किया जा सकता है और संभाला जा सकता है। B के लिए एक ही जो NullPointerException के साथ विफल रहता है। लेकिन जब मैं C में अपने आप पर एक NullPointerException फेंकने का प्रयास करता हूं तो प्रोग्राम संकलित नहीं होता है। और जब मैं D में अपनी खुद की रनटाइम अपवाद को परिभाषित करने का प्रयास करता हूं तो मुझे वही त्रुटि मिलती है। तो:

मैं जावा के समान ही कैसे कर सकता हूं?

// -*- compile-command: "javac expr.java && java expr"; -*- 

class expr 
{ 
    class A 
    { 
     int y; 
     {{ y = 0/0; }} 
    } 

    class B 
    { 
     Integer x = null; 
     int y; 
     {{ y = x.intValue(); }} 
    } 

    class C 
    { 
     {{ throw new NullPointerException(); }} 
    } 

    class Rex extends RuntimeException {} 

    class D 
    { 
     {{ throw new Rex(); }} 
    } 

    void run() 
    { 
     try { A a = new A(); } 
     catch (Exception e) { System.out.println (e); } 

     try { B b = new B(); } 
     catch (Exception e) { System.out.println (e); } 

     try { C c = new C(); } 
     catch (Exception e) { System.out.println (e); } 

     try { D d = new D(); } 
     catch (Exception e) { System.out.println (e); } 
    } 

    public static void main (String argv[]) 
    { 
     expr e = new expr(); 
     e.run(); 
    } 
} 
+0

@AlexWien आप कक्षा और वस्तु के बीच अंतर जानते हैं? ;-) – ceving

+0

हां, लेकिन उस उदाहरण के प्रारंभकर्ता मौजूद नहीं हैं, मैं केवल स्थिर प्रारंभिक जानता था। – AlexWien

उत्तर

13

initializer must be able to complete normally

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

उदाहरण के लिए

,

public class StaticThrow { 
    static int foo = 0; 
    {{ if (Math.sin(3) < 0.5) { throw new ArithmeticException("Heya"); } else { foo = 3; } }} 
    public static void main(String[] args) { 
     StaticThrow t = new StaticThrow(); 
     System.out.println(StaticThrow.foo); 
    } 
} 

compiles, और जब रन फेंकता

Exception in thread "main" java.lang.ArithmeticException: Heya 
     at StaticThrow.<init>(StaticThrow.java:3) 
     at StaticThrow.main(StaticThrow.java:5) 
+0

'0/0' में कोड पथ कहां है? – ceving

+4

कंपाइलर यह देखने के लिए पर्याप्त कोड का विश्लेषण नहीं करता है कि वह हमेशा फेंक देगा। आपके उदाहरणों में, आपने '{{कुछ फेंक दिया है; }} 'स्थिर प्रारंभिक में, और यह स्पष्ट है। कुछ ऐसा करने का प्रयास करें जो हमेशा सत्य रहेगा, लेकिन स्पष्ट नहीं है, '{{if (Math.sin (3) <0।5) {नया अंकगणित अपवाद फेंक दो; } और {जो कुछ भी; }}} '। –

+1

धन्यवाद! 'अगर (सच) फेंक ...' भी पर्याप्त है। – ceving

5

जावा न्यूनतम सुविधाओं के लिए बनाया गया है और जब वहाँ ऐसा करने के लिए एक बहुत अच्छा कारण है जटिलता केवल जोड़ा गया है। जावा नहीं पूछता है; क्यों नहीं, यह पूछता है; क्या मुझे वास्तव में इसका समर्थन करने की ज़रूरत है? (और फिर भी कभी-कभी नहीं;)

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

संकलक इस कोड को संकलित करने के लिए बनाया जा सकता है लेकिन यह किसी भी उपयोग के होने की संभावना नहीं है।


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

जांचे हुए अपवादों घोषित किया जाना चाहिए और वहाँ एक स्थिर में जाँच अपवाद घोषित करने के लिए कोई रास्ता नहीं है या एक उदाहरण प्रारंभिक ब्लॉक।

इसके बजाय आप चेक अपवाद को पकड़ और संभाल सकते हैं या लपेट सकते हैं। (या चाल का उपयोग कर, यह rethrow)

+0

और अनचेक अपवाद कैसे बनाएं? – ceving

+2

अनचेक अपवाद 'रनटाइम अपवाद' का विस्तार करते हैं। अपवाद लेने का कोई अच्छा तरीका नहीं है जिसे अन्यथा चेक किया जाएगा, उदाहरण के लिए 'IOException'', और इसे अनचेक कर दें। लेकिन अगर आप एक नया प्रकार बनाते हैं जो सीधे या अप्रत्यक्ष रूप से 'रनटाइम अपवाद' को बढ़ाता है, तो आप 'थ्रो' क्लॉज जोड़ने के बिना इसका एक उदाहरण फेंक सकते हैं। – cHao

1
{ throw new Rex(); } 

इसका मतलब है कि उदाहरण के ठीक से प्रारंभ कभी नहीं की जाएगी। ऐसी स्थिति होनी चाहिए जहां इंस्टेंस को ठीक से शुरू किया जा सके। जैसे

{ if(true) { throw new Rex(); } } //It doesn't complain here 

तो अपवाद उत्पन्न की जा रही एक जाँच-अपवाद तो आप इसके निर्माता के throws खंड में जोड़ने चाहिए। जैसे

public class MyObject { 
    { 
     //... 
      throw new Exception(); 
     //... 
    } 

    public MyObject() throws Exception { 

    } 
} 
2

आप वास्तव में एक प्रारंभ ब्लॉक में एक अपवाद फेंक करने की अनुमति है, लेकिन आप, "फेंकता" कीवर्ड के साथ सभी कंस्ट्रक्टर्स चिह्नित करना होगा आपका अपवाद एक जाँच से एक है।

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

वर्ग फू {

{{ 
    if(1 == 1) { 
     throw new Exception(); 
    } 
}} 

public Foo() throws Exception { 

} 

}

आशा इस में कुछ स्पष्ट किया बातें।

1

http://www.artima.com/designtechniques/initializationP.html से

The code inside an instance initializer may not return. Except in the case of anonymous inner classes, an instance initializer may throw checked exceptions only if the checked exceptions are explicitly declared in the throws clause of every constructor in the class. Instance initializers in anonymous inner classes, on the other hand, can throw any exception.

+0

_ दूसरी ओर अज्ञात आंतरिक कक्षाओं में प्रारंभिक प्रारंभकर्ता, किसी भी अपवाद को फेंक सकते हैं।यह एक शक्तिशाली छोटी सुविधा है, इस विवरण को खोजने के लिए धन्यवाद – blueimpb

0

यह बयान जाहिरा तौर पर नहीं पहुंचा जा सकता है, जो जावा ना करे की कोशिश करता है के बाकी का कारण बन जाएगा।

1

यह जावा भाषा विशिष्टता (जावा एसई 7) के section 8.6 द्वारा कवर किया गया है।

It is a compile-time error if an instance initializer cannot complete normally (§14.21).

14.21 परिभाषित करता है कि इसका उपयोग पहुंचने योग्य नहीं है। विशेष

Every other statement S in a non-empty block that is not a switch block is reachable iff the statement preceding S can complete normally.

और

A break, continue, return, or throw statement cannot complete normally.

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

तो हम क्यों (निश्चित रूप से) पहुंचने योग्य बयान के साथ कार्यक्रमों को अस्वीकार करना चाहते हैं? क्योंकि वे लगभग निश्चित रूप से बग का प्रतिनिधित्व करते हैं (समाप्त कोड में)। (if बयान कुशल सशर्त संकलन का समर्थन करने के विचित्र व्यवहार करते हैं।)

कोई नहीं पहुंचा जा सकता बयान नहीं कर रहे हैं, तो क्यों उदाहरण initialers (क्रम में गैर instantiable वर्गों का समर्थन करने के लिए नहीं निर्माताओं के लिए एक आवश्यकता) सामान्य रूप से पूरा करने में सक्षम होना चाहिए? क्योंकि इसके लिए गैर-स्थानीय विश्लेषण की आवश्यकता होती है जो जावा उचित रूप से सरल रहने के लिए नहीं करता है और रखरखाव के दौरान पुन: व्यवस्थित कोड के आदेश में केवल एक कथन छोड़ दिया जा सकता है।

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

संबंधित मुद्दे