क्या जावा में लेबल विराम एक अच्छा अभ्यास है?


82

मैं 2001 के कुछ पुराने कोड को देख रहा हूं और इस कथन पर आया हूं:

   else {
     do {
       int c = XMLDocumentFragmentScannerImpl.this.scanContent();
       if (c == 60) {
         XMLDocumentFragmentScannerImpl.this.fEntityScanner.scanChar();
         XMLDocumentFragmentScannerImpl.this.setScannerState(1);
         break label913;
       }

मैंने इसे पहले कभी नहीं देखा था, और यहां लेबल के टूटने की खोज की:

http://docs.oracle.com/javase/tutorial/java/nutsandbolts/branch.html

क्या यह अनिवार्य रूप से कार्य नहीं करता है goto? क्या इसका उपयोग करना भी अच्छा अभ्यास है? यह मुझे असहज करता है।


2
कहाँ label913परिभाषित किया गया है?
निकोले कुजनेत्सोव

1
इस मामले में, बहुत बड़े स्विच स्टेटमेंट के अंत में लगभग 200 लाइनें।
avgvstvs

जारी रखें और लेबल नाम कोड के उस भाग को संसाधित करने के लिए कोड बना देगा जहां ब्लॉक को एक लेबल के साथ चिह्नित किया गया था
user_CC

5
इस मामले में, फिर, समस्या स्विच स्टेटमेंट का आकार है!
सिरिल का

8
यह उत्पन्न कोड (वास्तव में एक पार्सर) जैसा दिखता है। उत्पन्न कोड के साथ बहुत सारे ट्रिक का उपयोग किया जाता है जो हाथ से लिखे गए कोड में उपयोग नहीं किया जाएगा (मुख्यतः क्योंकि वे पीढ़ी को आसान बनाते हैं)।
पारसीफाल

जवाबों:


120

नहीं, यह एक गोटो की तरह नहीं है, क्योंकि आप नियंत्रण प्रवाह के दूसरे भाग में "नहीं" जा सकते हैं।

आपके द्वारा जुड़े पृष्ठ से:

ब्रेक स्टेटमेंट लेबल स्टेटमेंट को समाप्त करता है; यह लेबल पर नियंत्रण के प्रवाह को स्थानांतरित नहीं करता है। नियंत्रण प्रवाह को लेबल (समाप्त) कथन के तुरंत बाद बयान में स्थानांतरित कर दिया जाता है।

इसका मतलब है कि आप केवल उन छोरों को तोड़ सकते हैं जिन्हें वर्तमान में निष्पादित किया जा रहा है।

इस उदाहरण पर विचार करें:

first:
for( int i = 0; i < 10; i++) {
  second:
  for(int j = 0; j < 5; j ++ )
  {
    break xxx;
  }
}

third:
for( int a = 0; a < 10; a++) {

}

आप बदल सकते xxxके साथ firstया second(बाहरी या भीतरी पाश को तोड़ने के लिए), के बाद से दोनों छोरों, निष्पादित किया जा रहा है जब आप हिट breakबयान है, लेकिन जगह xxxके साथ thirdसंकलन नहीं होंगे।


1
@user_CC वास्तव में नहीं, फिर भी आप नियंत्रण प्रवाह से बाहर नहीं जा सकते। एक लेबल जारी केवल लेबल किए गए लूप के अगले पुनरावृत्ति को शुरू करेगा और केवल तभी काम करेगा जब उस लूप को पहले ही निष्पादित किया जा रहा हो।
थॉमस

3
इसलिए यदि मैं उपयोग करता हूं break first;, तो कंपाइलर लाइन पर वापस जाने के बाद क्या होगा first:और उन छोरों को फिर से निष्पादित करेगा?
अनेगेहोर

15
@ जॉनीकोडर नं।, (अंत) लेबल वाले लूप break first;को तोड़ देगा first, अर्थात यह जारी रहेगा third। दूसरी ओर continue first;की वर्तमान यात्रा खत्म हो जाएगा firstऔर तोड़ secondकि के साथ और के अगले मूल्य के साथ जारी रहेगा iमें first
थॉमस

1
@ TheTechExpertGuy अच्छी तरह से, वास्तव में नहीं। यह केवल gotoकमोबेश उसी तरह का है if-elseजैसा कि एक बयान में है। गोटो के "अधिक लचीले" होते हैं जैसे "कहीं भी जाते हैं", उदाहरण के लिए लूप से पहले की स्थिति में (वास्तव में कि पुरानी भाषाएं लूप को कैसे लागू करती थीं: "अगर शर्त पूरी नहीं हुई, तो लूप बॉडी (फिर से शुरू) पर जाएं) । मुझे हाल ही में उनसे निपटना पड़ा है और मेरा विश्वास है: gotoगांड का असली दर्द होता है जबकि लेबल टूटता नहीं है।
थॉमस

1
@ TheTExExpertGuy आपका स्वागत है :) - चूंकि आप एक शुरुआत कर रहे हैं, मुझे एक बार फिर सलाह देने में आनाकानी महसूस हो रही है: gotoC ++ का समर्थन करने पर भी इसका उपयोग बिल्कुल न करें । लगभग हमेशा एक बेहतर तरीका है उन चीजों को हल करने का जो आपको बाद में बहुत सारे सिरदर्द से बचाएंगी। प्रलोभन आ सकता है ... विरोध!
थॉमस

16

यह उतना भयानक नहीं है gotoक्योंकि यह केवल लेबल किए गए कथन के अंत में नियंत्रण भेजता है (आमतौर पर एक लूप निर्माण)। जो चीज gotoअनुपयोगी बनाती है, वह यह है कि विधि स्रोत में उच्चतर पाए जाने वाले लेबल सहित कहीं भी यह एक मनमानी शाखा है, ताकि आपके पास घर में उगने वाला लूपिंग व्यवहार हो सके। जावा में लेबल-ब्रेक कार्यक्षमता उस प्रकार की पागलपन की अनुमति नहीं देती है क्योंकि नियंत्रण केवल आगे बढ़ता है।

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


6
@ Boann: मेरा मतलब यह नहीं है कि गोटो सभी संदर्भों में पूरी तरह से बुराई है। यह पॉइंटर अंकगणित, ऑपरेटर ओवरलोडिंग, और स्पष्ट मेमोरी प्रबंधन जैसी उन चीजों में से एक है जो जावा के रचनाकारों ने तय की थी कि यह परेशानी के लायक नहीं है। और 90% गोटो से अधिक लगने वाले COBOL कार्यक्रमों को पढ़ने के बाद, मुझे दुख नहीं है कि उन्होंने इसे जावा से बाहर छोड़ दिया।
नाथन ह्यूजेस

1
ओह, आप सही थे पहली बार @ नथनहुग्स, गोटो बहुत बुरी बुराई है। बिल्कुल नहीं, लेकिन हाँ, मैं एक के लिए सभी स्थितियों में यह याद नहीं है।
धारणा

2
गोटो लेबल की तुलना में अधिक "उपयोगी" हो सकता है, @ बॉन, लेकिन यह उनके रखरखाव की लागत से पूरी तरह से बाहर है। लेबल जादू की छड़ी नहीं हैं जो गोटो हैं, और यह एक अच्छी बात है।
डेविड एसएन

9

हमेशा breakनई विधि से प्रतिस्थापित करना संभव है ।

दो सूचियों में किसी भी सामान्य तत्वों के लिए कोड जाँच पर विचार करें:

List list1, list2;

boolean foundCommonElement = false;
for (Object el : list1) {
    if (list2.contains(el)) {
        foundCommonElement = true;
        break;
    }
}

आप इसे इस तरह से फिर से लिख सकते हैं:

boolean haveCommonElement(List list1, List list2) {
    for (Object el : list1) {
        if (list2.contains(el)) {
            return true;
        }
    }
    return false;
}

बेशक, दो सूचियों के बीच के सामान्य तत्वों की जांच करना बेहतर list1.retainAll(new HashSet<>(list2))है कि विधि का उपयोग अतिरिक्त मेमोरी के O(n)साथ करें O(n), या दोनों सूचियों को क्रमबद्ध करें O(n * log n)और फिर सामान्य तत्वों को खोजें O(n)


मेरी राय में यह लगभग हमेशा सही दृष्टिकोण है। goto(संभावित) हानिकारक है क्योंकि यह आपको कई जगह भेज सकता है - यह बिल्कुल स्पष्ट नहीं है कि क्या पूरा किया जा रहा है; हेल्पर फंक्शन बनाने से अगले लड़के को स्पष्ट सीमा मिलती है कि आप क्या करने की कोशिश कर रहे हैं और आप कहाँ करने जा रहे हैं, और यह आपको कार्यक्षमता के उस टुकड़े को नाम देने का मौका देता है। इस तरह से और अधिक स्पष्ट।
एथनबस्टड

@ethanbustad लेकिन यह लेबल के बारे में है break, नहीं goto। ज़रूर, यहाँ दिखाया गया रिफैक्टिंग दोनों मामलों में एक अच्छा विचार है। लेकिन लेबल breakलगभग असम्बद्ध नहीं है और कोड के रूप gotoमें स्पैगेटीफ़ाइंग करने की संभावना है।
अंडरस्कोर_ड

यह उदाहरण बहुत ही भयानक है, अगर इस पर काम नहीं किया जाता है, तो यहां लेबल बेकार है।
दीराकांट

8

इस उत्तर के बाकी हिस्सों को पढ़ने से पहले, कृपया गो टू स्टेटमेंट को ध्यान में रखते हुए हानिकारक पढ़ें । यदि आप इसे पूर्ण रूप से नहीं पढ़ना चाहते हैं, तो यहां मैं मुख्य बिंदु पर विचार करूंगा:

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

या रीफ़्रेज़ करने के लिए, समस्या gotoयह है कि प्रोग्राम कोड के एक ब्लॉक के बीच में आ सकता है, प्रोग्रामर को उस बिंदु पर प्रोग्राम स्टेट को समझने के बिना। मानक ब्लॉक-ओरिएंटेड कंस्ट्रक्शन को स्पष्ट रूप से स्टेट ट्रांजेक्शन के लिए डिज़ाइन किया गया है, एक लेबल breakका उद्देश्य प्रोग्राम को एक विशिष्ट ज्ञात स्थिति (लेबल वाले ब्लॉक से बाहर) तक ले जाना है।

एक वास्तविक विश्व अनिवार्यता कार्यक्रम में, राज्य स्पष्ट रूप से ब्लॉक सीमाओं से परिसीमित नहीं है, इसलिए यह संदिग्ध है कि क्या लेबल breakएक अच्छा विचार है। यदि ब्लॉक ब्लॉक के बाहर से दिखाई देने वाली स्थिति को बदलता है, और ब्लॉक से बाहर निकलने के लिए कई बिंदु हैं, तो एक लेबल breakआदिम के बराबर है goto। एकमात्र अंतर यह है कि अनिश्चित स्थिति वाले ब्लॉक के बीच में उतरने की संभावना के बजाय, आप अनिश्चित स्थिति वाले एक नए ब्लॉक की शुरुआत करते हैं।

इसलिए, सामान्य तौर पर, मैं एक लेबल breakको खतरनाक मानूंगा। मेरी राय में यह एक संकेत है कि ब्लॉक को एक फ़ंक्शन में परिवर्तित किया जाना चाहिए, जिसमें सीमित दायरे तक पहुंच होगी।

हालांकि, यह उदाहरण कोड स्पष्ट रूप से एक पार्सर जनरेटर का उत्पाद था (ओपी ने टिप्पणी की कि यह एक्सरेसेस सोर्स कोड था)। और पार्सर जनरेटर (या सामान्य रूप में कोड जनरेटर) अक्सर उत्पन्न कोड के साथ स्वतंत्रता लेते हैं, क्योंकि उन्हें राज्य का सही ज्ञान है और मनुष्यों को इसे समझने की आवश्यकता नहीं है।


मैं सहमत नहीं हूँ। breakकई मौकों पर काफी उपयोगी है। उदाहरण के लिए, जब आप कुछ मूल्य की तलाश कर रहे हैं जो कई ऑर्डर किए गए स्रोतों से आ सकते हैं। आप एक-एक करके कोशिश कर रहे हैं, और जब पहली मिल जाए, तो आप break। की तुलना में यह अधिक सुरुचिपूर्ण कोड है if / else if / else if / else if। (कम से कम यह कम लाइनें हैं।) एक विधि के संदर्भ में सब कुछ स्थानांतरित करना हमेशा व्यावहारिक नहीं हो सकता है। एक और मामला है, अगर आप सशर्त रूप से कुछ नेस्टेड स्तरों से तोड़ रहे हैं। संक्षेप में, यदि आपको कोई पसंद नहीं है break, तो आपको returnएक विधि के अंत के अलावा कहीं और पसंद नहीं है ।
ओंद्रा kaižka

संदर्भ के लिए; "To go वक्तव्य हानिकारक माना" लिखा गया था जब तरह बातें doऔर whileमौजूद नहीं था और सभी को उपयोग कर रहा था if(.. ) gotoहर जगह के बजाय। यह भाषा डिजाइनरों को प्रोत्साहित करने के लिए था जैसे चीजों के लिए समर्थन जोड़ने के लिए doऔर while। अफसोस की बात यह है कि एक बार जब बैंडवाले ने इसे रोल करना शुरू कर दिया तो अज्ञानी लोगों द्वारा breakइसे "केवल एक बार फंसे हुए" लूप्स में फेंकने की अपवाद वाली ट्रेन में बदल दिया गया और अपवादों को फेंक दिया गया कि कौन जानता है कि सभी (दुर्लभ) मामलों gotoमें क्लीनर और कम हानिकारक हैं।
ब्रेंडन

1

यह एक gotoकथन जैसा नहीं है, जहां आप प्रवाह नियंत्रण को पीछे की ओर उछालते हैं। एक लेबल आपको दिखाता है (प्रोग्रामर) जहां ब्रेक हुआ है। इसके अलावा, प्रवाह नियंत्रण अगले बयान में स्थानांतरित कर दिया जाता है break

इसका उपयोग करने के बारे में, मुझे लगता है कि व्यक्तिगत रूप से इसका कोई बड़ा उपयोग नहीं है क्योंकि एक बार जब आप हजारों लाइनों के लायक कोड लिखना शुरू करते हैं तो यह महत्वहीन हो जाता है। लेकिन फिर से, यह उपयोग के मामले पर निर्भर करेगा।


for(int i = 0; i < 1; i++) { do_something(); if(I_want_to_go_backwards) { i = 0; continue; } }
ब्रेंडन

1

आशय व्यक्त करने का एक साफ तरीका, कम से कम मेरी राय में, कोड के टुकड़े को डालने के लिए हो सकता है जिसमें लूप को एक अलग विधि में और बस returnइसे से अलग किया जाए।

उदाहरण के लिए, इसे बदलें:

someLabel:
for (int j = 0; j < 5; j++)
{
    // do something
    if ...
        break someLabel;
}

इस मामले में:

private void Foo() {
    for (int j = 0; j < 5; j++)
    {
        // do something
        if ...
            return;
    }
}

यह अन्य भाषाओं में डेवलपर्स के लिए अधिक मुहावरेदार है जो भविष्य में आपके कोड के साथ काम कर सकता है (या भविष्य में आप )।

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