जावा 8 में अपवाद प्रकार के अपवाद की एक अजीब विशेषता


85

इस साइट पर एक और उत्तर के लिए कोड लिखते समय मैं इस विशिष्टता में आया:

static void testSneaky() {
  final Exception e = new Exception();
  sneakyThrow(e);    //no problems here
  nonSneakyThrow(e); //ERRROR: Unhandled exception: java.lang.Exception
}

@SuppressWarnings("unchecked")
static <T extends Throwable> void sneakyThrow(Throwable t) throws T {
  throw (T) t;
}

static <T extends Throwable> void nonSneakyThrow(T t) throws T {
  throw t;
}

सबसे पहले, मैं काफी उलझन में हूं कि sneakyThrowकॉल कंपाइलर के लिए ठीक क्यों है । Tजब किसी अनियंत्रित अपवाद प्रकार का कहीं कोई उल्लेख नहीं है , तो यह किस प्रकार का अनुमान लगा सकता है?

दूसरा, यह स्वीकार करते हुए कि यह काम करता है, फिर कंपाइलर nonSneakyThrowकॉल पर शिकायत क्यों करता है ? वे बहुत एक जैसे लगते हैं।

जवाबों:


66

टी का sneakyThrowअनुमान है RuntimeException। इसके प्रकार प्रकार के अनुमान ( http://docs.oracle.com/javase/specs/jls/se8/html/jls-18.html ) पर लैन्गॉज कल्पना से पीछा किया जा सकता है )

सबसे पहले, धारा 18.1.3 में एक नोट है:

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

यह कुछ भी प्रभावित नहीं करता है, लेकिन यह हमें रिज़ॉल्यूशन सेक्शन (18.4) की ओर इशारा करता है, जिसे एक विशेष मामले के साथ अनुमानित अपवाद प्रकारों पर अधिक जानकारी मिली है:

... नहीं तो, बाध्य सेट होता है अगर throws αi, और αi के समुचित ऊपरी सीमा अधिक से अधिक, कर रहे हैं, Exception, Throwable, और Object, तो ती = RuntimeException

यह मामला लागू होता है sneakyThrow- एकमात्र ऊपरी सीमा है Throwable, इसलिए Tअनुमान के RuntimeExceptionअनुसार अनुमान लगाया जाता है , इसलिए यह संकलन करता है। विधि का शरीर सारहीन है - अनियंत्रित कास्ट रनटाइम पर सफल होता है क्योंकि यह वास्तव में नहीं होता है, एक विधि को छोड़कर जो संकलन-समय की जाँच अपवाद प्रणाली को हरा सकता है।

nonSneakyThrowउस विधि के रूप में संकलित नहीं करता है, Tजिसका निम्न बाउंड मिला है Exception(यानी स्वयं या उससे अधिक Tका एक सुपरस्क्रिप्ट होना चाहिए ), जो कि एक प्रकार का अपवाद है, जिस प्रकार के साथ इसे बुलाया जा रहा है, ताकि इसका अनुमान लगाया जा सके ।ExceptionExceptionTException


1
@ माक्सिमम का मतलब आपको sneakyThrowकॉल करना होगा । का अनुमान के बारे में विशेष नियमों throws Tरूपों जावा 7. के विनिर्देश में मौजूद नहीं था
मार्को Topolnik

1
लघु नाइटिक: इन nonSneakyThrow, "सुपरसाइप" नहीं Tहोना चाहिए Exception, Exceptionक्योंकि यह कॉल साइट पर संकलन समय पर घोषित किए गए तर्क का प्रकार है।
लौगलिक

1
@llogiq यदि मैंने युक्ति को सही ढंग से पढ़ा है, तो यह एक निचली बाउंड Exceptionऔर एक ऊपरी बाउंड मिला है Throwable, इसलिए कम से कम ऊपरी बाउंड, जो परिणामित अनुमान प्रकार है, है Exception
12

1
@llogiq ध्यान दें कि तर्क का प्रकार केवल एक निम्न प्रकार की सीमा को निर्धारित करता है क्योंकि तर्क का कोई भी सुपरस्क्रिप्ट भी स्वीकार्य है।
मार्को टोपोलनिक

2
"या Exceptionस्वयं" वाक्यांश पाठक के लिए उपयोगी हो सकता है, लेकिन आम तौर पर, यह ध्यान दिया जाना चाहिए कि विनिर्देश हमेशा "उपप्रकार" और "सुपरटेप" शब्दों का उपयोग "स्वयं सहित" के अर्थ में करता है ...
Holger

17

यदि एक प्रकार के चर के लिए टाइप इंफ़ेक्शन एकल ऊपरी बाउंड उत्पन्न करता है, तो आमतौर पर ऊपरी बाउंड को समाधान के रूप में चुना जाता है। उदाहरण के लिए, यदि T<<Number, समाधान है T=Number। हालाँकि Integer, Floatआदि भी बाधा को संतुष्ट कर सकते हैं, उन्हें चुनने का कोई अच्छा कारण नहीं है Number

यह भी throws Tजावा 5-7 के लिए मामला था T<<Throwable => T=Throwable:। (डरपोक फेंक समाधान सभी स्पष्ट <RuntimeException>प्रकार तर्क थे, अन्यथा<Throwable> यह अनुमान है।)

Java8 में, लैम्ब्डा की शुरुआत के साथ, यह समस्याग्रस्त हो जाता है। इस मामले पर विचार करें

interface Action<T extends Throwable>
{
    void doIt() throws T;
}

<T extends Throwable> void invoke(Action<T> action) throws T
{
    action.doIt(); // throws T
}    

यदि हम एक खाली मेमने के साथ आह्वान करते हैं, तो क्या होगा T?

    invoke( ()->{} ); 

एकमात्र बाधा Tएक ऊपरी सीमा है Throwable। जावा के पहले चरण में, T=Throwableअनुमान लगाया जाएगा। यह रिपोर्ट मैंने दर्ज की।

लेकिन यह बहुत मूर्खतापूर्ण है, अनुमान लगाने के लिए Throwable, एक खाली ब्लॉक से बाहर, एक चेक किया गया अपवाद। रिपोर्ट में एक समाधान प्रस्तावित किया गया था (जिसे जाहिरा तौर पर जेएलएस द्वारा अपनाया गया है) -

If E has not been inferred from previous steps, and E is in the throw clause, 
and E has an upper constraint E<<X,
    if X:>RuntimeException, infer E=RuntimeException
    otherwise, infer E=X. (X is an Error or a checked exception)

यानी यदि ऊपरी सीमा है Exceptionया Throwable, RuntimeExceptionसमाधान के रूप में चुनें । इस मामले में, ऊपरी सीमा के किसी विशेष उपप्रकार को चुनने का एक अच्छा कारण है।


X:>RuntimeExceptionआपके अंतिम उदाहरण स्निपेट का क्या अर्थ है ?
मर्सौफ

1

के साथ sneakyThrow, प्रकार एक विशिष्ट प्रकार के बिनाT एक बंधा हुआ सामान्य प्रकार का चर है (क्योंकि ऐसा कोई प्रकार नहीं है जहां से प्रकार आ सकता है)।

साथ nonSneakyThrow, प्रकार Tतर्क के रूप में एक ही प्रकार, इस प्रकार आपके उदाहरण में, है Tकी nonSneakyThrow(e);है Exception। जैसा testSneaky()कि एक फेंक घोषित नहीं करता है Exception, एक त्रुटि दिखाई जाती है।

ध्यान दें कि यह चेक किए गए अपवादों के साथ जेनरिक का एक ज्ञात हस्तक्षेप है।


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