एक अपवाद को पकड़ना और उसे पुन: प्रस्तुत करना, लेकिन यह अपवाद नहीं है


10

मैं कोड पर ठोकर खाई कुछ इस तरह लग रही है:

void run() {
    try {
        doSomething();
    } catch (Exception ex) {
        System.out.println("Error: " + ex);
        throw ex;
    }
}

void doSomething() {
    throw new RuntimeException();
}

यह कोड मुझे आश्चर्यचकित करता है क्योंकि ऐसा लगता है कि run()-मैथोड एक को फेंकने में सक्षम है Exception, क्योंकि यह पकड़ता है Exceptionऔर फिर इसे हटा देता है, लेकिन विधि को फेंकने की घोषणा नहीं की जाती है Exceptionऔर जाहिर तौर पर इसे करने की आवश्यकता नहीं है। यह कोड बस ठीक है (जावा 11 में कम से कम)।

मेरे उम्मीद होगी कि मैं घोषणा करने के लिए होता throws Exceptionमें run()-method।

अतिरिक्त जानकारी

इसी तरह से, अगर doSomethingफेंकने की घोषणा की जाती है , IOExceptionतो केवल कोमथोड IOExceptionमें घोषित करने की आवश्यकता run()होती है, भले ही Exceptionपकड़ा गया हो और फिर से फेंक दिया गया हो ।

void run() throws IOException {
    try {
        doSomething();
    } catch (Exception ex) {
        System.out.println("Error: " + ex);
        throw ex;
    }
}

void doSomething() throws IOException {
    // ... whatever code you may want ...
}

सवाल

जावा आमतौर पर स्पष्टता पसंद करता है, इस व्यवहार के पीछे क्या कारण है? क्या यह हमेशा से ऐसा ही रहा है? जावा भाषा विशिष्टता में क्या है जो run()विधि को throws Exceptionऊपर दिए गए कोड स्निपेट में घोषित करने की आवश्यकता नहीं है? (अगर मैं इसे जोड़ देता, तो IntelliJ मुझे चेतावनी देता है कि Exceptionइसे कभी नहीं फेंका जाए)।


3
दिलचस्प। आप क्या संकलक का उपयोग कर रहे हैं? यदि यह आईडीई कंपाइलर है, तो इसके साथ जांचें javac- मैं उन मामलों में भाग रहा हूं जहां ग्रहण संकलक अधिक उदार था।
एम। प्रोखोरोव

2
मैं Openjdk-8 पर इस व्यवहार को पुन: पेश कर सकता हूं। उल्लेखनीय रूप से -source 1.6ध्वज का संकलन उम्मीद के अनुरूप संकलन त्रुटि को जन्म देता है। स्रोत संगतता 7 के साथ संकलन संकलन त्रुटि को नहीं बढ़ाता
Vogel612

1
ऐसा लगता है कि कंपाइलर जावा 7 के बाद से अधिक स्मार्ट है और वास्तविक अपवाद पर अधिक जाँच करता है जिसे फेंका जा सकता है।
माइकल

2
यह प्रश्न कोई डुप्लिकेट नहीं है और इसका उत्तर मुझे दिए गए लिंक में मिल सकता हैIn detail, in Java SE 7 and later, when you declare one or more exception types in a catch clause, and rethrow the exception handled by this catch block, the compiler verifies that the type of the rethrown exception meets the following conditions : 1. 1. The try block is able to throw it. 2. There are no other preceding catch blocks that can handle it. 3. It is a subtype or supertype of one of the catch clause's exception parameters.
michalk

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

जवाबों:


0

मैंने JLSआपके प्रश्न में पूछे अनुसार स्कैन नहीं किया है, इसलिए कृपया इस उत्तर को नमक के दाने के साथ लें। मैं इसे एक टिप्पणी करना चाहता था, लेकिन यह बहुत बड़ा था।


मुझे कई बार मजाकिया लगता है कि javacकुछ मामलों में (जैसे आपके मामले में) कितना सुंदर "स्मार्ट" है, लेकिन बाद में नियंत्रित करने के लिए बहुत सी अन्य चीजों को छोड़ देता है JIT। इस मामले में, यह सिर्फ इतना है कि संकलक "बता सकता है" कि केवल RuntimeExceptionपकड़ा जाएगा। यह स्पष्ट है, यह केवल एक चीज है जिसे आप फेंक देते हैं doSomething। यदि आप अपना कोड इसमें थोड़ा बदलते हैं:

void run() {
    try {
        doSomething();
    } catch (Exception ex) {
        Exception ex2 = new Exception();
        System.out.println("Error: " + ex);
        throw ex2;
    }
}

आपको एक अलग व्यवहार दिखाई देगा, क्योंकि अब javacयह बता सकता है कि एक नया है Exceptionजिसे आप फेंक रहे हैं, आपके द्वारा पकड़े गए से संबंधित है।

लेकिन चीजें आदर्श से बहुत दूर हैं, आप संकलक को फिर से "ट्रिक" कर सकते हैं:

void run() {
    try {
        doSomething();
    } catch (Exception ex) {
        Exception ex2 = new Exception();
        ex2 = ex;
        System.out.println("Error: " + ex);
        throw ex2;
    }
}

IMO, क्योंकि ex2 = ex;यह फिर से विफल नहीं होना चाहिए, लेकिन यह करता है।

बस इस मामले में यह संकलित किया गया था javac 13+33


मैंने कुछ लिंक में पढ़ा कि किसी ने प्रदान किया कि यदि आप कैच-ब्लॉक में पकड़े गए अपवाद को फिर से असाइन करते हैं, तो कंपाइलर स्मार्ट नहीं हो पा रहा है। मुझे लगता है कि इस मामले में भी कुछ ऐसा ही लागू होता है। कंपाइलर जानता है कि ex2अपवाद को फेंक दिया जाएगा, यह मूल रूप से बनाया गया था, Exceptionलेकिन फिर से पुन: असाइन किया गया है ex, और इसलिए कंपाइलर स्मार्ट नहीं हो पा रहा है।
साइमन फोर्सबर्ग

@SimonForsberg किसी के लिए एक जुनून है जो JLSआ सकता है और इसे साबित करने के लिए आवश्यक उद्धरण प्रदान करता है; दुर्भाग्य से मेरे पास उनके पास नहीं है।
यूजीन

रिकॉर्ड के लिए, जब मैं खुद को पकड़े गए अपवाद का एक पुनर्मूल्यांकन शामिल करने के लिए कैच ब्लॉक को बदल देता हूं (ex = ex; ) , तो हेयुरिस्टिक अब लागू नहीं होता है। यह व्यवहार सभी स्रोत स्तरों के लिए 7 से 11 के बीच और शायद 13 पर लागू होता है
Vogel612

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