रिटर्न स्टेटमेंट के बिना रिटर्न प्रकार के साथ जावा विधि


228

प्रश्न 1:

निम्नलिखित कोड रिटर्न स्टेटमेंट के बिना संकलन क्यों करता है?

public int a() {
    while(true);
}

सूचना: यदि मैं थोड़ी देर के बाद वापसी जोड़ता हूं तो मुझे ए Unreachable Code Error

प्रश्न 2:

दूसरी ओर, निम्न कोड क्यों संकलित करता है,

public int a() {
    while(0 == 0);
}

हालांकि निम्नलिखित नहीं है।

public int a(int b) {
    while(b == b);
}

2
2 प्रश्न के उत्तरार्ध के लिए धन्यवाद, stackoverflow.com/questions/16789832/… की नकल नहीं ।
टीजे क्राउडर

जवाबों:


274

प्रश्न 1:

निम्नलिखित कोड रिटर्न स्टेटमेंट के बिना संकलन क्यों करता है?

public int a() 
{
    while(true);
}

यह JLS§8.4.7 द्वारा कवर किया गया है :

यदि किसी विधि को रिटर्न प्रकार (.48.4.5) घोषित किया जाता है, तो कंपाइल-टाइम त्रुटि तब होती है जब विधि का शरीर सामान्य रूप से पूरा हो सकता है (.114.1)।

दूसरे शब्दों में, रिटर्न प्रकार के साथ एक विधि को केवल रिटर्न स्टेटमेंट का उपयोग करके वापस लौटना चाहिए जो मूल्य वापसी प्रदान करता है; विधि को "उसके शरीर के अंत को छोड़ने" की अनुमति नहीं है। विधि बॉडी में रिटर्न स्टेटमेंट के बारे में सटीक नियमों के लिए statements14.17 देखें।

एक विधि के लिए रिटर्न टाइप करना संभव है और फिर भी कोई रिटर्न स्टेटमेंट नहीं है। यहाँ एक उदाहरण है:

class DizzyDean {
    int pitch() { throw new RuntimeException("90 mph?!"); }
}

चूंकि कंपाइलर जानता है कि लूप कभी भी समाप्त नहीं होगा ( trueयह हमेशा सच है, निश्चित रूप से), यह जानता है कि फ़ंक्शन "सामान्य रूप से वापस नहीं" हो सकता है (इसके शरीर के अंत को छोड़ दें), और इस तरह यह ठीक है कि नहीं return

प्रश्न 2:

दूसरी ओर, निम्न कोड क्यों संकलित करता है,

public int a() 
{
    while(0 == 0);
}

हालांकि निम्नलिखित नहीं है।

public int a(int b)
{
    while(b == b);
}

में 0 == 0मामला है, संकलक जानता है कि पाश समाप्त कभी नहीं होगा (कि 0 == 0हमेशा सच हो जाएगा)। लेकिन यह पता नहीं है कि के लिए b == b

क्यों नहीं?

कंपाइलर निरंतर अभिव्यक्तियों (.215.28) को समझता है । उद्धरण ( 15.2 - अभिव्यक्ति के रूप (क्योंकि अजीब तरह से यह वाक्य .215.28 में नहीं है) :

कुछ अभिव्यक्तियों में एक मूल्य होता है जिसे संकलन समय पर निर्धारित किया जा सकता है। ये निरंतर अभिव्यक्ति हैं (.215.28)।

आपके b == bउदाहरण में, क्योंकि इसमें एक चर शामिल है, यह एक स्थिर अभिव्यक्ति नहीं है और इसे संकलन समय पर निर्धारित नहीं किया गया है। हम देख सकते हैं कि यह इस मामले में हमेशा सही साबित होने वाला है (हालाँकि यदि bdouble, जैसा कि QBrute ने कहा है , तो हमें आसानी से मूर्ख बनाया जा सकता है Double.NaN, जो कि स्वयं नहीं ==है ), लेकिन JLS केवल यह निर्दिष्ट करता है कि लगातार अभिव्यक्तियाँ संकलन समय पर निर्धारित की जाती हैं , यह संकलक को गैर-स्थिर अभिव्यक्तियों का मूल्यांकन करने की कोशिश करने की अनुमति नहीं देता है। bayou.io ने इसके लिए एक अच्छा बिंदु क्यों नहीं उठाया : यदि आप संकलन समय पर चर को शामिल करने वाले भावों को निर्धारित करने की कोशिश के लिए नीचे जाना शुरू करते हैं, तो आप कहां रुकते हैं? b == bस्पष्ट है (एर, गैर के लिएNaNमान), लेकिन किस बारे में a + b == b + a? या (a + b) * 2 == a * 2 + b * 2? स्थिरांक पर रेखा खींचना समझ में आता है।

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


34

यह निर्दिष्ट प्रकार का मान प्रदान करने के लिए एक वादा के रूप में एक विधि वापसी प्रकार के बारे में सोच नहीं करने के लिए दिलचस्प हो सकता है, लेकिन एक वादा के रूप में नहीं है कि एक मूल्य के वापस जाने के लिए नहीं निर्दिष्ट प्रकार के। इस प्रकार, यदि आप कभी कुछ वापस नहीं करते हैं, तो आप वादा नहीं तोड़ रहे हैं, और इसलिए निम्न में से कोई भी कानूनी हैं:

  1. हमेशा के लिए लूपिंग:

    X foo() {
        for (;;);
    }
  2. हमेशा के लिए पुनर्भरण:

    X foo() {
        return foo();
    }
  3. एक अपवाद बाहर फेंक:

    X foo() {
        throw new Error();
    }

(मुझे लगता है कि इस बारे में सोचने के लिए पुनरावर्तन एक मजेदार लगता है: संकलक का मानना ​​है कि विधि प्रकार का मान लौटाएगी X(जो कुछ भी है), लेकिन यह सच नहीं है, क्योंकि कोई कोड मौजूद नहीं है जिसका कोई विचार है कि कैसे बनाया जाए या एक खरीद X।)


8

बाइट कोड को देखते हुए, यदि जो लौटाया जा रहा है वह परिभाषा से मेल नहीं खाता है, तो आपको एक संकलन त्रुटि मिलेगी।

उदाहरण:

for(;;) बायोटेक दिखाएगा:

L0
    LINENUMBER 6 L0
    FRAME SAME
    GOTO L0

किसी भी रिटर्न बायोटेक की कमी पर ध्यान दें

यह कभी भी रिटर्न नहीं मारता है, और इस प्रकार गलत प्रकार वापस नहीं करता है।

तुलना के लिए, एक विधि की तरह:

public String getBar() { 
    return bar; 
}

निम्नलिखित बायोटेक वापस करेगा:

public java.lang.String getBar();
    Code:
      0:   aload_0
      1:   getfield        #2; //Field bar:Ljava/lang/String;
      4:   areturn

"आरटर्न" पर ध्यान दें जिसका अर्थ है "एक संदर्भ लौटाएं"

अब अगर हम निम्नलिखित करें:

public String getBar() { 
    return 1; 
}

निम्नलिखित बायोटेक वापस करेगा:

public String getBar();
  Code:
   0:   iconst_1
   1:   ireturn

अब हम देख सकते हैं कि परिभाषा का प्रकार वापसी के प्रकार से मेल नहीं खाता है, जिसका अर्थ है कि रिटर्न इंट।

तो वास्तव में क्या यह नीचे आता है कि यदि विधि में वापसी पथ है, तो उस पथ को वापसी प्रकार से मेल खाना चाहिए। लेकिन ऐसे उदाहरण हैं बायटेकोड में, जहां कोई भी वापसी पथ उत्पन्न नहीं होता है, और इस प्रकार नियम का कोई टूटना नहीं है।

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