سؤال

لقد فوجئت مؤخرًا عندما وجدت أنه من الممكن الحصول على بيان إرجاع في كتلة نهائية في Java.

يبدو أن الكثير من الناس يعتقدون أنه من السيئ القيام بما هو موضح في "لا تعود في جملة أخيرا'.خدش أعمق قليلا، وجدت أيضا 'عودة Java لا تكون دائمًا' والذي يعرض بعض الأمثلة الرهيبة جدًا لأنواع أخرى من التحكم في التدفق في الكتل النهائية.

لذا، سؤالي هو، هل يمكن لأي شخص أن يعطيني مثالاً حيث تنتج عبارة الإرجاع (أو أي تحكم آخر في التدفق) في كتلة نهائية كودًا أفضل/أكثر قابلية للقراءة؟

هل كانت مفيدة؟

المحلول

الأمثلة التي قدمتها هي سبب كاف ل لا استخدم التحكم في التدفق من النهاية.

حتى لو كان هناك مثال مفتعل حيث يكون الأمر "أفضل"، فكر في المطور الذي يتعين عليه الحفاظ على الكود الخاص بك لاحقًا والذي قد لا يكون على علم بالتفاصيل الدقيقة.ربما يكون هذا المطور المسكين هو أنت....

نصائح أخرى

لقد واجهت وقتًا عصيبًا حقًا في تعقب الخلل الذي حدث منذ سنوات بسبب هذا.وكان الرمز شيء من هذا القبيل:

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

ما حدث هو أنه تم طرح الاستثناء في بعض التعليمات البرمجية الأخرى.تم القبض عليه وتسجيله وإعادة إلقائه داخل somethingThatThrewAnException() طريقة.لكن الاستثناء لم يتم نشره في الماضي problemMethod().بعد وقت طويل من النظر في هذا، قمنا أخيرًا بتتبعه وصولاً إلى طريقة الإرجاع.كانت طريقة الإرجاع في الكتلة الأخيرة تعمل بشكل أساسي على إيقاف الاستثناء الذي حدث في كتلة المحاولة من الانتشار لأعلى على الرغم من عدم اكتشافه.

كما قال الآخرون، على الرغم من أنه من القانوني العودة من الكتلة النهائية وفقًا لمواصفات Java، إلا أن هذا أمر سيئ ولا ينبغي القيام به.

سوف يحذرك javac من العودة أخيرًا إذا كنت تستخدم -Xlint:finally.في الأصل، لم يُصدر javac أي تحذيرات - إذا كان هناك خطأ ما في الكود، فمن المفترض أن يفشل في التجميع.ولسوء الحظ فإن التوافق مع الإصدارات السابقة يعني أنه لا يمكن حظر الحماقة البارعة غير المتوقعة.

يمكن طرح الاستثناءات من الكتل النهائية، ولكن في هذه الحالة يكون السلوك المعروض هو ما تريده بالتأكيد.

تعد إضافة هياكل التحكم والإرجاع إلى كتل last{} مجرد مثال آخر على إساءة استخدام "لمجرد أنك تستطيع" والمنتشرة في جميع لغات التطوير تقريبًا.كان جيسون على حق في اقتراحه أنه يمكن أن يصبح بسهولة كابوسًا للصيانة - فالحجج ضد العائدات المبكرة من الوظائف تنطبق بشكل أكبر على حالة "العائدات المتأخرة" هذه.

أخيرًا، توجد الكتل لغرض واحد، وهو السماح لك بترتيب نفسك تمامًا، بغض النظر عما حدث في كل التعليمات البرمجية السابقة.يتمثل هذا بشكل أساسي في إغلاق/تحرير مؤشرات الملفات واتصالات قاعدة البيانات وما إلى ذلك، على الرغم من أنني أرى أنه يتم تمديده ليقول إضافة تدقيق مخصص.

أي شيء يؤثر على إرجاع الوظيفة يجب أن يكون موجودًا في كتلة المحاولة{}.حتى لو كانت لديك طريقة يمكنك من خلالها التحقق من حالة خارجية، وإجراء عملية تستغرق وقتًا طويلاً، ثم التحقق من تلك الحالة مرة أخرى في حالة أنها أصبحت غير صالحة، فستظل ترغب في إجراء التحقق الثاني داخل المحاولة{} - إذا بقيت بالداخل أخيرًا{} وفشلت العملية الطويلة، فسوف تقوم بعد ذلك بالتحقق من هذه الحالة مرة أخرى دون داع.

اختبار رائع بسيط:

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 ^^
-----------------------------------------------------------------------------

سؤال:

كانت إحدى النقاط المثيرة للاهتمام بالنسبة لي هي معرفة كيفية تعامل Groovy مع العوائد الضمنية.في Groovy من الممكن "العودة" من طريقة ما ببساطة مع ترك قيمة في النهاية (بدون إرجاع).ماذا تعتقد أنه سيحدث، إذا قمت بإلغاء التعليق على جارٍ تشغيل المواضيع.إزالة (..) سطر في العبارة النهائية - هل سيحل هذا محل قيمة الإرجاع العادية ("موافق") ويغطي الاستثناء؟!

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top