जावा में एक गोटो स्टेटमेंट के लिए वैकल्पिक


83

जावा में गोटो कीवर्ड के लिए एक वैकल्पिक कार्य क्या है ?

चूंकि जावा में गोटो नहीं है।


10
@harigm: यदि आप कोड की तरह का एक उदाहरण है कि आप लिखते थे दे सकते हैं अगर goto जावा में उपलब्ध है? मुझे लगता है कि इसमें अधिक महत्वपूर्ण मुद्दा निहित है।
पॉलीजेन लुब्रीकेंट

3
@harigm: मैं दूसरी पालीगीन, क्या आप अपने प्रश्न को अपडेट करने के लिए शामिल कर सकते हैं कि आपके प्रोग्राम को गोटो की आवश्यकता क्यों है?
हर कोई

13
लोग हमेशा एक गोटो का उपयोग करने के बारे में बात करते हैं, लेकिन मुझे लगता है कि वास्तव में एक अच्छा वास्तविक दुनिया का उपयोग मामला है जो बहुत अच्छी तरह से जाना जाता है और उपयोग किया जाता है .. यही है, एक फ़ंक्शन से लौटने से पहले कुछ कोड निष्पादित करना सुनिश्चित करता है .. आमतौर पर इसका विमोचन ताले या क्या नहीं, लेकिन मेरे मामले में मैं वापसी से ठीक पहले एक ब्रेक के लिए कूदना चाहूंगा ताकि मैं अनिवार्य सफाई कर सकूं। बेशक एक कार्यक्रम गोटो के साथ पूरी जगह पर हो सकता है, भयानक होगा, लेकिन अगर विधि निकायों के लिए प्रतिबंधित है तो ऐसा नहीं लगता है कि जब तक आप एक सम्मेलन का पालन करते हैं तब तक बुरा नहीं होता है (केवल कार्यों के अंत में कूदो, कभी वापस मत आना)
मैट वोल्फ

7
आप अच्छी कंपनी में हैं। Linus Torvalds ने गोटो kerneltrap.org/node/553 का जुनून से बचाव किया है । निस्संदेह परियोजना सिक्का से सबसे उल्लेखनीय चूक है।
फ्लेश

7
@MattWolfe अंत में उस उदाहरण में काम नहीं करता है?
एंड्रेस रिओप्रियो

जवाबों:


83

आप एक लेबल BREAK कथन का उपयोग कर सकते हैं :

search:
    for (i = 0; i < arrayOfInts.length; i++) {
        for (j = 0; j < arrayOfInts[i].length; j++) {
            if (arrayOfInts[i][j] == searchfor) {
                foundIt = true;
                break search;
            }
        }
    }

हालाँकि, ठीक से डिज़ाइन किए गए कोड में, आपको GOTO कार्यक्षमता की आवश्यकता नहीं होनी चाहिए।


88
यह आपको रैप्टर से नहीं बचाएगा!
बॉबी

25
आपको ठीक से डिज़ाइन किए गए कोड में गोटो कार्यक्षमता की आवश्यकता क्यों नहीं होनी चाहिए?
१०:४२ पर रोजर्मुशरूम

13
क्योंकि विधानसभा ही इसका उपयोग करने की अनुमति है। एक बयान, एक बयान के लिए, एक करते समय, एक फॉर्च्यूनर, एक फ़ंक्शन कॉल, ये सभी एक नियंत्रित और अनुमानित तरीके से इस्तेमाल किए जाने वाले गोटो बयान हैं। कोडांतरक के स्तर पर, यह हमेशा GOTO होगा, लेकिन आपको उस कार्यक्षमता की आवश्यकता नहीं होनी चाहिए जो आपको शुद्ध GOTO देता है - फ़ंक्शंस और लूप / कंट्रोल स्टेटमेंट पर इसका एकमात्र लाभ यह है कि यह आपको किसी भी कोड के बीच में कूदने देता है, कहीं भी । और वह 'लाभ' स्वयं 'स्पेगेटी कोड' की परिभाषा है।

1
@whatsthebeef यहां 1968 का प्रसिद्ध पत्र एग्जर डब्ल्यू। डेज्क्ट्रा ने बताया है कि वह एफई को हानिकारक क्यों मानते हैं
थोमांस्की


42

gotoजावा में अवधारणा के बराबर कोई प्रत्यक्ष नहीं है । कुछ निर्माण हैं जो आपको क्लासिक के साथ कुछ चीजें करने की अनुमति देते हैं goto

  • breakऔर continueबयान आप एक पाश या स्विच बयान में एक ब्लॉक से बाहर कूद करने के लिए अनुमति देते हैं।
  • एक लेबल किया गया कथन और break <label>आपको दिए गए तरीके (या इनिशियलाइज़र ब्लॉक) के भीतर किसी भी स्तर पर एक मनमाना यौगिक विवरण से बाहर निकलने की अनुमति देता है।
  • यदि आप एक लूप स्टेटमेंट लेबल करते हैं, तो आप continue <label>आंतरिक लूप से बाहरी लूप के अगले पुनरावृत्ति के साथ जारी रख सकते हैं ।
  • अपवाद को फेंकना और पकड़ना आपको एक विधि कॉल के कई स्तरों से (प्रभावी रूप से) कूदने की अनुमति देता है। (हालांकि, अपवाद अपेक्षाकृत महंगे हैं और "साधारण" नियंत्रण प्रवाह 1 करने के लिए एक बुरा तरीका माना जाता है ।)
  • और हां, है return

इन जावा निर्माणों में से कोई भी आपको वर्तमान कथन के रूप में नेस्टिंग के समान स्तर पर पीछे या शाखा में एक बिंदु पर शाखा करने की अनुमति नहीं देता है। वे सभी एक या अधिक घोंसले के शिकार (गुंजाइश) स्तर से बाहर कूदते हैं और वे सभी (अलग-अलग continue) नीचे की ओर कूदते हैं। यह प्रतिबंध पुराने बेसिक, फोरट्रान और कोबोल कोड 2 में निहित गोटो "स्पेगेटी कोड" सिंड्रोम से बचने में मदद करता है ।


1- अपवादों का सबसे महंगा हिस्सा अपवाद वस्तु और उसके स्टैकट्रेस का वास्तविक निर्माण है। यदि आपको वास्तव में, "सामान्य" प्रवाह नियंत्रण के लिए अपवाद हैंडलिंग का उपयोग करने की आवश्यकता है, तो आप अपवाद ऑब्जेक्ट का प्रचार / पुन: उपयोग कर सकते हैं, या fillInStackTrace()विधि को ओवरराइड करने वाले कस्टम अपवाद वर्ग बना सकते हैं । नकारात्मक पक्ष यह है कि अपवाद के printStackTrace()तरीके आपको उपयोगी जानकारी नहीं देंगे ... क्या आपको कभी उन्हें कॉल करने की आवश्यकता है।

2 - स्पेगेटी कोड सिंड्रोम ने संरचित प्रोग्रामिंग दृष्टिकोण को जन्म दिया , जहां आप उपलब्ध भाषा निर्माण के अपने उपयोग में सीमित हैं। इसे BASIC , Fortran और COBOL पर लागू किया जा सकता है , लेकिन इसके लिए देखभाल और अनुशासन आवश्यक है। gotoपूरी तरह से छुटकारा पाना एक व्यावहारिक रूप से बेहतर समाधान था। यदि आप इसे किसी भाषा में रखते हैं, तो हमेशा कुछ विदूषक होता है जो इसका दुरुपयोग करेगा।


लूपिंग निर्माण जैसे (...) {} और के लिए (...) {} आपको स्पष्ट रूप से मनमाने स्थान पर जाने के बिना कोड के ब्लॉक दोहराने की अनुमति देता है। इसके अलावा, विधि myMethod को कॉल करती है () आपको कहीं और पाए गए कोड को निष्पादित करने की अनुमति देता है और समाप्त होने पर वर्तमान ब्लॉक में वापस आ जाता है। इन सभी का उपयोग गोटो की कार्यक्षमता को बदलने के लिए किया जा सकता है, जबकि गोटो की अनुमति देने में विफल होने की सामान्य समस्या को रोका जा सकता है ।
क्रिस नावा

@ क्रिस - यह सच है, लेकिन ज्यादातर भाषाएं जो गोटो का समर्थन करती हैं, उनके पास जावा लूप निर्माण के करीब एनालॉग भी हैं।
स्टीफन C

1
@ क्रिस - क्लासिक फोरट्रान के लिए 'लूप्स' हैं और क्लासिक कोबोल में लूपिंग कंस्ट्रक्शन भी हैं (हालांकि मैं विवरणों को याद नहीं कर सकता)। केवल क्लासिक BASIC में कोई स्पष्ट लूपिंग निर्माण नहीं है ...
स्टीफन C

31

बस मज़े के लिए, यहाँ जावा में एक GOTO कार्यान्वयन है।

उदाहरण:

   1 public class GotoDemo {
   2     public static void main(String[] args) {
   3         int i = 3;
   4         System.out.println(i);
   5         i = i - 1;
   6         if (i >= 0) {
   7             GotoFactory.getSharedInstance().getGoto().go(4);
   8         }
   9         
  10         try {
  11             System.out.print("Hell");
  12             if (Math.random() > 0) throw new Exception();            
  13             System.out.println("World!");
  14         } catch (Exception e) {
  15             System.out.print("o ");
  16             GotoFactory.getSharedInstance().getGoto().go(13);
  17         }
  18     }
  19 }

इसे चलाना:

$ java -cp bin:asm-3.1.jar GotoClassLoader GotoDemo           
   3
   2
   1
   0
   Hello World!

क्या मुझे "इसका उपयोग नहीं करना है?"


1
मैं इसका इस्तेमाल नहीं
करूंगा

1
बग: Math.random()वापसी कर सकते हैं 0. यह होना चाहिए = =
poitroae

हां अच्छा है। कुछ भी है कि केवल bytecode हैकरी द्वारा लागू किया जा सकता है वास्तव में जावा नहीं है ...
स्टीफन C

क्या ऐसा ही कुछ है जो लाइन नंबरों के बजाय लेबल का समर्थन करता है?
बेह्रोज़।

1
एक कार्यान्वयन का लिंक टूट गया है।
लार्स

17

हालांकि कुछ टिप्पणीकारों और डाउनवोटर्स का तर्क है कि यह गोटो नहीं है , नीचे दिए गए जावा स्टेटमेंट से उत्पन्न बायटेकोड वास्तव में बताता है कि ये कथन वास्तव में गोटो शब्दार्थ व्यक्त करते हैं ।

विशेष रूप से, do {...} while(true);लूप की स्थिति का मूल्यांकन नहीं करने के लिए दूसरे उदाहरण में लूप को जावा कंपाइलरों द्वारा अनुकूलित किया जाता है।

कूदते हुए आगे

label: {
  // do stuff
  if (check) break label;
  // do more stuff
}

बायोटेक में:

2  iload_1 [check]
3  ifeq 6          // Jumping forward
6  ..

पीछे की ओर कूदना

label: do {
  // do stuff
  if (check) continue label;
  // do more stuff
  break label;
} while(true);

बायोटेक में:

 2  iload_1 [check]
 3  ifeq 9
 6  goto 2          // Jumping backward
 9  ..

कैसे करते हैं / जबकि पीछे की ओर कूदते हैं? यह अभी भी ब्लॉक से बाहर निकलता है। काउंटर उदाहरण: लेबल: do {System.out.println ("बैकवर्ड"); लेबल जारी रखें;) जबकि (झूठा); मुझे लगता है कि आपके उदाहरण में (सच) वही है जो बैकवर्ड जंप के लिए जिम्मेदार है।
बेन हॉलैंड

@ बेनहोलैंड: continue labelपीछे की ओर कूदना है
लुकास एडर

मुझे अब भी यकीन नहीं हो रहा है। जारी बयान एक, जबकि, या डू-लूप के वर्तमान पुनरावृत्ति को रोक देता है। जारी रहना लूप के शरीर के अंत में जाता है, जो बाद में लूप को नियंत्रित करने वाली बूलियन अभिव्यक्ति के लिए मूल्यांकन किया जाता है। जबकि जो पीछे की ओर कूद रहा है वह जारी नहीं है। देखें docs.oracle.com/javase/tutorial/java/nutsandbolts/branch.html
बेन हॉलैंड

@ बेंहोलैंड: तकनीकी रूप से आप सही कह रहे हैं। तार्किक दृष्टिकोण से, यदि // do stuffऔर // do more stuffब्याज के बयान हैं , तो continue label "प्रभाव पड़ता है" पीछे की ओर कूदने ( while(true)कोर्स के बयान के कारण )। मुझे नहीं पता था कि यह इतना सटीक सवाल था, हालांकि ...
लुकास एडर

2
@BenHolland: मैंने जवाब अपडेट किया। while(true)एक में संकलक द्वारा अनुवाद किया है gotoबाईटकोड आपरेशन। जैसा trueकि एक निरंतर शाब्दिक है, संकलक इस अनुकूलन को कर सकता है और इसके लिए कुछ भी मूल्यांकन नहीं करना पड़ता है। इसलिए, मेरा उदाहरण वास्तव में एक गोटो है, पीछे की ओर कूदते हुए ...
लुकास एडर

5

यदि आप वास्तव में गोटो स्टेटमेंट जैसा कुछ चाहते हैं, तो आप हमेशा नामित ब्लॉकों को तोड़ने की कोशिश कर सकते हैं।

आपको लेबल को तोड़ने के लिए ब्लॉक के दायरे में रहना होगा:

namedBlock: {
  if (j==2) {
    // this will take you to the label above
    break namedBlock;
  }
}

मैं आपको इस बात पर व्याख्यान नहीं दूंगा कि आपको गोटो से क्यों बचना चाहिए - मुझे लगता है कि आप पहले से ही इसका जवाब जानते हैं।


2
मैंने इसे अपने SO प्रश्न में यहाँ से लागू करने का प्रयास किया । यह वास्तव में आपको "ऊपर दिए गए लेबल" पर नहीं ले जाता है, शायद मैंने लेखक के बयानों की गलत व्याख्या की है, लेकिन स्पष्टता के लिए मैं इसे बाहरी ब्लॉक ("लेबल" ब्लॉक) के अंत तक ले जाऊंगा, जो नीचे है तुम कहाँ टूट रहे हो इसलिए आप ऊपर की तरफ "टूट" नहीं सकते। कम से कम मेरी समझ तो यही है।
नेमस्पेस

4
public class TestLabel {

    enum Label{LABEL1, LABEL2, LABEL3, LABEL4}

    /**
     * @param args
     */
    public static void main(String[] args) {

        Label label = Label.LABEL1;

        while(true) {
            switch(label){
                case LABEL1:
                    print(label);

                case LABEL2:
                    print(label);
                    label = Label.LABEL4;
                    continue;

                case LABEL3:
                    print(label);
                    label = Label.LABEL1;
                    break;

                case LABEL4:
                    print(label);
                    label = Label.LABEL3;
                    continue;
            }
            break;
        }
    }

    public final static void print(Label label){
        System.out.println(label);
    }

यह एक StackOverFlowException में परिणाम देगा आप इसे लंबे समय से चला रहे हैं, इस प्रकार मेरी आवश्यकता है।
केविन पार्कर

3
@ केविन: यह एक स्टैक ओवरफ्लो की ओर कैसे ले जाएगा? इस एल्गोरिथ्म में कोई पुनरावृत्ति नहीं है ...
लुकास ईडर

1
यह बहुत मूल प्रमाण की तरह दिखता है कि किसी भी कार्यक्रम को "गोटो" का उपयोग किए बिना लिखा जा सकता है - इसे "लेबल" चर के साथ थोड़ी देर के लूप में बदलकर जो किसी भी गोटो से दस गुना बदतर है।
gnasher729

3

स्टीफन लिखते हैं:

दो निर्माण हैं जो आपको क्लासिक गोटो के साथ कुछ चीजें करने की अनुमति देते हैं।

एक और...

मैट वोल्फ लिखते हैं:

लोग हमेशा गोटो का उपयोग न करने के बारे में बात करते हैं, लेकिन मुझे लगता है कि वास्तव में एक अच्छा विश्व उपयोग का मामला है जो बहुत अच्छी तरह से जाना जाता है और उपयोग किया जाता है .. यही है, एक फ़ंक्शन से लौटने से पहले कुछ कोड निष्पादित करना सुनिश्चित करता है .. आमतौर पर इसका विमोचन ताले या क्या नहीं, लेकिन मेरे मामले में मैं वापसी से ठीक पहले एक ब्रेक पर कूदना चाहूंगा ताकि मैं अनिवार्य सफाई कर सकूं।

try {
    // do stuff
    return result;  // or break, etc.
}
finally {
    // clean up before actually returning, even though the order looks wrong.
}

http://docs.oracle.com/javase/tutorial/essential/exceptions/finally.html

अंततः ब्लॉक हमेशा निष्पादित होता है जब कोशिश ब्लॉक से बाहर निकलता है। यह सुनिश्चित करता है कि अंत में ब्लॉक निष्पादित किया जाता है भले ही एक अप्रत्याशित अपवाद हो। लेकिन अंत में अपवाद अपवाद से अधिक के लिए उपयोगी है - यह प्रोग्रामर को गलती से वापसी, जारी रखने या तोड़ने के द्वारा बाईपास किए गए सफाई कोड से बचने की अनुमति देता है। अंत में ब्लॉक में सफाई कोड डालना हमेशा एक अच्छा अभ्यास होता है, तब भी जब कोई अपवाद प्रत्याशित न हो।

अंत में जुड़े हुए मूर्खतापूर्ण साक्षात्कार का प्रश्न है: यदि आप एक कोशिश {} ब्लॉक से लौटते हैं, लेकिन आपके अंत में एक वापसी {} भी है, तो कौन सा मान लौटाया जाता है?


2
मैं असहमत हूं कि यह एक मूर्खतापूर्ण साक्षात्कार प्रश्न है। एक अनुभवी जावा प्रोग्रामर को पता होना चाहिए कि क्या होता है, अगर केवल यह समझना है कि ब्लॉक returnमें क्यों डालना finallyएक बुरा विचार है। (और यहां तक ​​कि अगर ज्ञान कड़ाई से आवश्यक नहीं है, तो मैं एक प्रोग्रामर से चिंतित होऊंगा, जिसे जानने की उत्सुकता नहीं थी ...)
स्टीफन सी

1

सबसे आसान है:

int label = 0;
loop:while(true) {
    switch(state) {
        case 0:
            // Some code
            state = 5;
            break;

        case 2:
            // Some code
            state = 4;
            break;
        ...
        default:
            break loop;
    }
}

0

नीचे दिए गए कोड को आज़माएं। इससे मेरा काम बनता है।

for (int iTaksa = 1; iTaksa <=8; iTaksa++) { // 'Count 8 Loop is  8 Taksa

    strTaksaStringStar[iCountTaksa] = strTaksaStringCount[iTaksa];

    LabelEndTaksa_Exit : {
        if (iCountTaksa == 1) { //If count is 6 then next it's 2
            iCountTaksa = 2;
            break  LabelEndTaksa_Exit;
        }

        if (iCountTaksa == 2) { //If count is 2 then next it's 3
            iCountTaksa = 3;
            break  LabelEndTaksa_Exit;
        }

        if (iCountTaksa == 3) { //If count is 3 then next it's 4
            iCountTaksa = 4;
            break  LabelEndTaksa_Exit;
        }

        if (iCountTaksa == 4) { //If count is 4 then next it's 7
            iCountTaksa = 7;
            break  LabelEndTaksa_Exit;
        }

        if (iCountTaksa == 7) { //If count is 7 then next it's 5
            iCountTaksa = 5;
            break  LabelEndTaksa_Exit;
        }

        if (iCountTaksa == 5) { //If count is 5 then next it's 8
            iCountTaksa = 8;
            break  LabelEndTaksa_Exit;
        }

        if (iCountTaksa == 8) { //If count is 8 then next it's 6
            iCountTaksa = 6;
            break  LabelEndTaksa_Exit;
        }

        if (iCountTaksa == 6) { //If count is 6 then loop 1  as 1 2 3 4 7 5 8 6  --> 1
            iCountTaksa = 1;
            break  LabelEndTaksa_Exit;
        }
    }   //LabelEndTaksa_Exit : {

} // "for (int iTaksa = 1; iTaksa <=8; iTaksa++) {"

-1

गोटो के विकल्प के रूप में एक लेबल ब्रेक का उपयोग करें।


यह उत्तर है, और हमेशा बेमानी था
स्टीफन C

-1

जावा में नहीं है goto, क्योंकि यह कोड को असंरचित और पढ़ने में अस्पष्ट बनाता है । हालांकि, अगर आप उपयोग कर सकते हैं breakऔर continueके रूप में सभ्य के रूप गोटो अपनी समस्याओं के बिना।


ब्रेक का उपयोग करके आगे कूदना -

ahead: {
    System.out.println("Before break");
    break ahead;
    System.out.println("After Break"); // This won't execute
}
// After a line break ahead, the code flow starts from here, after the ahead block
System.out.println("After ahead");

आउटपुट :

Before Break
After ahead

जंप बैकवर्ड का उपयोग जारी है

before: {
    System.out.println("Continue");
    continue before;
}

इसके परिणामस्वरूप एक अनंत लूप होगा क्योंकि हर बार लाइन continue beforeनिष्पादित होने के बाद, कोड प्रवाह फिर से शुरू हो जाएगाbefore


2
जारी रखने के लिए पिछड़े कूदने पर आपका उदाहरण गलत है। आप लूप के शरीर के बाहर "जारी" का उपयोग नहीं कर सकते हैं, यह एक संकलन त्रुटि का कारण बनता है। एक लूप के अंदर, हालांकि, जारी रखें बस लूप सशर्त कूदता है। तो ऐसा कुछ है जबकि (सच) {जारी;} एक अनंत लूप होगा, लेकिन ऐसा तब (जबकि) उस मामले के लिए {} है।
बेन हॉलैंड
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.