जावा में आखिरकार ब्लॉक से लौटते हुए


177

मुझे हाल ही में यह जानकर आश्चर्य हुआ कि जावा में आखिरकार ब्लॉक में रिटर्न स्टेटमेंट संभव है।

ऐसा लगता है कि बहुत से लोग सोचते हैं कि यह एक बुरी बात है जैसा कि ' अंत में क्लॉज में वापस न आना ' में वर्णित है । थोड़ा गहराई से छानबीन करने पर, मैंने यह भी पाया कि ' जावा की वापसी हमेशा नहीं होती है ' जो अंत में ब्लॉक में अन्य प्रकार के प्रवाह नियंत्रण के कुछ बहुत ही भयानक उदाहरण दिखाता है।

तो, मेरा प्रश्न यह है कि क्या कोई मुझे एक उदाहरण दे सकता है जहां एक अंत में ब्लॉक में रिटर्न स्टेटमेंट (या अन्य प्रवाह नियंत्रण) बेहतर / अधिक रीडिंग कोड का उत्पादन करता है?

जवाबों:


90

आपके द्वारा दिए गए उदाहरण कारण हैं कि अंत से प्रवाह-नियंत्रण का उपयोग करें।

यहां तक ​​कि अगर एक वंचित उदाहरण है जहां यह "बेहतर" है, तो उस डेवलपर पर विचार करें जिसे बाद में आपके कोड को बनाए रखना है और जिसे सूक्ष्मता के बारे में पता नहीं हो सकता है। वो बेचारा विकासक भी आपको हो सकता है…।


5
ज़रूर। मुझे लगता है कि मैं मामले में पूछ रहा हूं कि कोई मुझे कुछ अच्छा करने के लिए वास्तव में सम्मोहक उदाहरण दे सकता है।
मैट शेपर्ड

@ दत्तशेपर्ड इन दोस, मैं अक्सर एक कोशिश
ब्लेक

148

मैं एक बग साल पहले नीचे ट्रैक करने के लिए वास्तव में कठिन समय था जो इसके कारण हुआ था। कोड कुछ इस तरह था:

Object problemMethod() {
    Object rtn = null;
    try {
        rtn = somethingThatThrewAnException();
    }
    finally {
        doSomeCleanup();
        return rtn;
    }
}

क्या हुआ कि अपवाद को किसी अन्य कोड में नीचे फेंक दिया गया। यह पकड़ा जा रहा था और somethingThatThrewAnException()विधि के भीतर लॉग इन किया और फिर से उखाड़ फेंका गया । लेकिन अपवाद पिछले प्रचार नहीं किया जा रहा था problemMethod()। इसे देखने के एक लंबे समय के बाद हमने अंत में इसे वापसी विधि पर नज़र रखी। अंत में ब्लॉक में वापसी की विधि मूल रूप से अपवाद को रोक रही थी जो कोशिश ब्लॉक में हुआ था, भले ही वह पकड़ा नहीं गया था।

जैसा कि अन्य लोगों ने कहा है, जबकि जावा युक्ति के अनुसार अंत में ब्लॉक से लौटना कानूनी है, यह एक बुरा काम है और ऐसा नहीं किया जाना चाहिए।


फिर रिटर्न कहां डालना चाहिए?
पारसेकर

@parsecer कुछ सही कहने के बाद मैं कहूंगा। थ्रू एवन एक्ससेप्शन () कोशिश ब्लॉक के अंदर
टियागो सिपर्ट

@parsecer, ?? बस इसे सामान्य तरीके से करें, आखिरकार।
पचेरियर

21

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

अपवादों को अंततः ब्लॉक से फेंक दिया जा सकता है, लेकिन उस मामले में प्रदर्शन व्यवहार लगभग निश्चित रूप से आप क्या चाहते हैं।


13

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

अंत में एक उद्देश्य के लिए ब्लॉक मौजूद हैं, जिससे आप अपने आप को पूरी तरह से साफ कर सकते हैं, चाहे वह सभी पूर्ववर्ती कोड में न हो। मुख्य रूप से यह फ़ाइल पॉइंटर्स, डेटाबेस कनेक्शन आदि को बंद / जारी कर रहा है, हालाँकि मैं देख सकता हूँ कि इसे bespoke काटने में जोड़ना कहा जा रहा है।

कुछ भी जो फ़ंक्शन की वापसी को प्रभावित करता है, कोशिश {} ब्लॉक में झूठ होना चाहिए। यहां तक ​​कि अगर आपके पास एक विधि थी जिससे आपने बाहरी राज्य की जांच की थी, एक समय लेने वाला ऑपरेशन किया था, तो उस स्थिति को फिर से जांचा कि यदि यह अमान्य हो गया है, तो आप फिर भी {} - अगर यह अंत में बैठ गया तो कोशिश के अंदर दूसरी जांच करना चाहेंगे {} और लंबे ऑपरेशन में विफल रहा, तो आप उस राज्य को दूसरी बार अनावश्यक रूप से जाँच रहे होंगे।


6

एक साधारण ग्रूवी टेस्ट:

public class Instance {

  List<String> runningThreads = new ArrayList<String>()

  void test(boolean returnInFinally) {

    println "\ntest(returnInFinally: $returnInFinally)"
    println "--------------------------------------------------------------------------"
    println "before execute"
    String result = execute(returnInFinally, false)
    println "after execute -> result: " + result
    println "--------------------------------------------------------------------------"

    println "before execute"
    try {
      result = execute(returnInFinally, true)
      println "after execute -> result: " + result
    } catch (Exception ex) {
      println "execute threw exception: " + ex.getMessage()
    }  
    println "--------------------------------------------------------------------------\n"

  }

  String execute(boolean returnInFinally, boolean throwError) {
      String thread = Thread.currentThread().getName()
      println "...execute(returnInFinally: $returnInFinally, throwError: $throwError) - thread: $thread"
      runningThreads.add(thread)
      try {
        if (throwError) {
          println "...error in execute, throw exception"
          throw new Exception("as you liked :-)")
        }
        println "...return 'OK' from execute"
        return "OK"
      } finally {
        println "...pass finally block"
        if (returnInFinally) return "return value from FINALLY ^^"
        // runningThreads.remove(thread)
      }
  }
}

Instance instance = new Instance()
instance.test(false)
instance.test(true)

आउटपुट:

test(returnInFinally: false)
-----------------------------------------------------------------------------
before execute
...execute(returnInFinally: false, throwError: false) - thread: Thread-116
...return 'OK' from execute
...pass finally block
after execute -> result: OK
-----------------------------------------------------------------------------
before execute
...execute(returnInFinally: false, throwError: true) - thread: Thread-116
...error in execute, throw exception
...pass finally block
execute threw exception: as you liked :-)
-----------------------------------------------------------------------------


test(returnInFinally: true)
-----------------------------------------------------------------------------
before execute
...execute(returnInFinally: true, throwError: false) - thread: Thread-116
...return 'OK' from execute
...pass finally block
after execute -> result: return value from FINALLY ^^
-----------------------------------------------------------------------------
before execute
...execute(returnInFinally: true, throwError: true) - thread: Thread-116
...error in execute, throw exception
...pass finally block
after execute -> result: return value from FINALLY ^^
-----------------------------------------------------------------------------

सवाल:

मेरे लिए एक दिलचस्प बिंदु यह देखना था कि ग्रूवी कैसे निहित रिटर्न से निपटता है। ग्रूवी में एक विधि से "वापसी" करना संभव है, बस अंत में एक मूल्य छोड़कर (वापसी के बिना)। आपको क्या लगता है कि अगर आप रनिंग थ्रेड्स को स्थानांतरित करते हैं। अंतिम विवरण में .remove (..) लाइन - यह नियमित रिटर्न वैल्यू ("ओके") को ओवरराइट करेगा और अपवाद को कवर करेगा ?!


0

एक finallyब्लॉक के अंदर से लौटने के कारण exceptionsखो जाएगा।

अंत में ब्लॉक के अंदर एक रिटर्न स्टेटमेंट किसी भी अपवाद का कारण होगा जिसे कोशिश में पकड़ा जा सकता है या ब्लॉक को छोड़ दिया जा सकता है।

जावा भाषा विशिष्टता के अनुसार :

यदि आर ब्लॉक का निष्पादन किसी अन्य कारण R के लिए अचानक पूरा हो जाता है, तो अंत में ब्लॉक निष्पादित किया जाता है, और फिर एक विकल्प है:

   If the finally block completes normally, then the try statement
   completes  abruptly for reason R.

   If the finally block completes abruptly for reason S, then the try
   statement  completes abruptly for reason S (and reason R is
   discarded).

नोट: जेएलएस 14.17 के अनुसार - एक रिटर्न स्टेटमेंट हमेशा अचानक पूरा होता है।

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