سؤال

هل هي ممارسة سيئة للقبض Throwable?

على سبيل المثال شيء من هذا القبيل:

try {
    // Some code
} catch(Throwable e) {
    // handle the exception
}

هل هذه ممارسة سيئة أم يجب أن نكون محددين قدر الإمكان؟

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

المحلول

يجب أن تكون محددًا قدر الإمكان.وإلا فإن الأخطاء غير المتوقعة قد تزحف بعيدًا بهذه الطريقة.

بجانب، Throwable أغلفة Error كذلك وهذا عادة لا توجد نقطة العودة.أنت لا تريد اكتشاف ذلك/التعامل معه، فأنت تريد أن يتوقف برنامجك على الفور حتى تتمكن من إصلاحه بشكل صحيح.

نصائح أخرى

هذه فكرة سيئة.في الواقع، حتى اصطياد Exception عادة ما تكون فكرة سيئة.دعونا نفكر في مثال:

try {
    inputNumber = NumberFormat.getInstance().formatNumber( getUserInput() );
} catch(Throwable e) {
    inputNumber = 10; //Default, user did not enter valid number
}

الآن، لنفترض أن getUserInput() يحظر لفترة من الوقت، ويقوم مؤشر ترابط آخر بإيقاف مؤشر الترابط الخاص بك بأسوأ طريقة ممكنة (يستدعي Thread.stop() ).سوف تلتقط كتلة الالتقاط الخاصة بك ملف ThreadDeath خطأ.هذا سيء للغاية.سلوك التعليمات البرمجية الخاصة بك بعد التقاط هذا الاستثناء غير محدد إلى حد كبير.

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

لديك ثلاثة خيارات أفضل:

1 - حدد الاستثناء (الاستثناءات) الذي تعرف كيفية التعامل معه بالضبط:

try {
    inputNumber = NumberFormat.getInstance().formatNumber( getUserInput() );
} catch(ParseException e) {
    inputNumber = 10; //Default, user did not enter valid number
}

2--أعد طرح أي استثناء واجهته ولا تعرف كيفية التعامل معه:

try {
    doSomethingMysterious();
} catch(Exception e) {
    log.error("Oh man, something bad and mysterious happened",e);
    throw e;
}

3 - استخدم الكتلة النهائية حتى لا تضطر إلى تذكر إعادة الرمي:

 Resources r = null;
 try {
      r = allocateSomeResources();
      doSomething(r);
 } finally {
     if(r!=null) cleanUpResources(r);
 }

كن على علم أيضًا أنه عندما تمسك Throwable, ، يمكنك أيضًا التقاط InterruptedException مما يتطلب معاملة خاصة.يرى التعامل مع InterruptedException لمزيد من التفاصيل.

إذا كنت تريد فقط اكتشاف الاستثناءات التي لم يتم التحقق منها، فقد تفكر أيضًا في هذا النمط

try {
   ...
} catch (RuntimeException exception) {
  //do something
} catch (Error error) {
  //do something
}

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

مباشرة من Javadoc من فئة الخطأ (والتي توصي بعدم اللحاق بهذه):

giveacodicetagpre.

ليست ممارسة سيئة إذا لم تتمكن من إخراج فقاعة استثناء من الأسلوب.

إنها ممارسة سيئة إذا كنت لا تستطيع حقا التعامل مع الاستثناء.من الأفضل إضافة "الرميات" إلى توقيع الطريقة من مجرد الصيد وإعادة رميها أو، أسوأ، لفها في RuntiMeexception وإعادة رميها.

اللحاق بالركض في بعض الأحيان إذا كنت تستخدم المكتبات التي ترمي الأخطاء فوق بحماس، وإلا فقد تقتل مكتبتك طلبك.

ومع ذلك، سيكون من الأفضل بموجب هذه الظروف لتحديد الأخطاء المحددة التي ألقيتها المكتبة فقط، بدلا من جميع الألغام.

قابلة للرياضة هي الفئة الأساسية لجميع الطبقات مما يمكن إلقاؤه (ليس باستثناءات فقط).هناك القليل يمكنك القيام به إذا قبضت على OutofmoryError أو kernelerror (انظر متى تم التقاط جافا.Lang.Error؟ )

يجب أن تكون الاستثناءات

كافية.

يعتمد على منطقك أو أن تكون أكثر تحديدا لخياراتك / إمكانياتك.إذا كان هناك أي استثناء محدد، فيمكنك أن تتفاعل بطريقة ذات معنى، فيمكنك التقاطه أولا والقيام بذلك.

إذا لم يكن هناك وأنت متأكد من أنك ستفعل نفس الشيء لجميع الاستثناءات والأخطاء (على سبيل المثال، فقم بالخروج برسالة خطأ)، مما لا يمثل مشكلة للقبض على Realable.

عادة ما تعقد الحالة الأولى ولن تلتقط.ولكن لا يزال هناك الكثير من الحالات التي يصطادها بشكل جيد.

على الرغم من أنه يوصف بأنه سيئة جدا الممارسة ، قد تجد في بعض الأحيان نادر الحالات التي ليست مفيدة فقط ولكن أيضا إلزامية.وإليك مثالين على ذلك.

في تطبيق ويب حيث يجب أن تظهر معنى كامل صفحة خطأ المستخدم.هذا الرمز تأكد من أن هذا يحدث كما هو كبير try/catch حول كل ما تبذلونه طلب handelers ( servlets, الدعامات الإجراءات ، أو أي وحدة تحكم ....)

try{
     //run the code which handles user request.
   }catch(Throwable ex){
   LOG.error("Exception was thrown: {}", ex);
     //redirect request to a error page. 
 }

}

وكمثال آخر ، تنظر لديك خدمة فئة والذي يقدم صندوق نقل الأعمال.هذا الأسلوب بإرجاع TransferReceipt إذا كان يتم نقل أو NULL إذا لم أستطع.

String FoundtransferService.doTransfer( fundtransferVO);

الآن التصوير تحصل على List التحويلات المالية من المستخدم يجب استخدام الخدمات المذكورة أعلاه أن تفعل كل منهم.

for(FundTransferVO fundTransferVO : fundTransferVOList){
   FoundtransferService.doTransfer( foundtransferVO);
}

ولكن ماذا سيحدث إذا أي استثناء يحدث ؟ يجب أن لا تتوقف ، كما نقل واحد قد يكون النجاح لا يجوز, يجب أن تبقي على الذهاب من خلال جميع المستخدمين List, و تظهر النتيجة على كل عملية تحويل.إذا كنت في نهاية المطاف مع هذا القانون.

for(FundTransferVO fundTransferVO : fundTransferVOList){
    FoundtransferService.doTransfer( foundtransferVO);
 }catch(Throwable ex){
    LOG.error("The transfer for {} failed due the error {}", foundtransferVO, ex);
  }
}

يمكنك تصفح الكثير من المشاريع المفتوحة المصدر أن نرى أن throwable هو حقا مؤقتا و التعامل معها.على سبيل المثال هنا هو البحث عن tomcat,struts2 و primefaces:

https://github.com/apache/tomcat/search?utf8=%E2%9C%93&q=catch%28Throwable https://github.com/apache/struts/search?utf8=%E2%9C%93&q=catch%28Throwable https://github.com/primefaces/primefaces/search?utf8=%E2%9C%93&q=catch%28Throwable

السؤال غامض بعض الشيء.هل تسأل "هل هو موافق للقبض Throwable"، أو" هل من المقبول التقاط أ Throwable ولا تفعل شيئا"؟كثير من الناس هنا أجابوا على السؤال الأخير، لكن هذه مسألة جانبية؛في 99% من الحالات، يجب ألا "تستهلك" أو تتجاهل الاستثناء، سواء كنت تصطاده Throwable أو IOException أو أيا كان.

إذا قمت بنشر الاستثناء، فإن الإجابة (مثل الإجابة على العديد من الأسئلة) هي "يعتمد ذلك".يعتمد الأمر على ما تفعله مع الاستثناء – لماذا تلتقطه.

مثال جيد على سبب رغبتك في اللحاق Throwable هو توفير نوع من التنظيف إذا كان هناك أي خطأ.على سبيل المثال، في JDBC، إذا حدث خطأ أثناء إحدى المعاملات، فقد ترغب في التراجع عن المعاملة:

try {
  …
} catch(final Throwable throwable) {
  connection.rollback();
  throw throwable;
}

لاحظ أنه لا يتم تجاهل الاستثناء، بل يتم نشره.

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

بشكل عام كنت تريد تجنب اصطياد Errorولكن يمكنني التفكير (على الأقل) في حالتين محددتين حيث يكون من المناسب القيام بذلك:

  • تريد إيقاف تشغيل التطبيق استجابةً للأخطاء، خصوصًا AssertionError وهو غير ضار.
  • هل تقوم بتنفيذ آلية تجميع سلاسل المحادثات المشابهة لـ ExecutorService.submit() يتطلب منك إعادة توجيه الاستثناءات إلى المستخدم حتى يتمكن من التعامل معها.

إذا كنا نستخدم Realable ، فهذا يغطي خطأ أيضا وهذا هو.

مثال.

giveacodicetagpre.

}

الإخراج:

giveacodicetagpre.

يمكن أن يكون superclass لجميع الأخطاء والمفتنة. إذا كنت تستخدم Reallable في جملة Catch، فلن يصطاد جميع الاستثناءات فحسب، فسيحصل أيضا على جميع الأخطاء.يتم إلقاء الأخطاء من قبل JVM للإشارة إلى مشاكل خطيرة لا تهدف إلى التعامل معها بواسطة تطبيق.أمثلة نموذجية لذلك هي OutofMemoryError أو Stackoverflowerror.كلاهما ناتج عن المواقف الموجودة خارج السيطرة على التطبيق ولا يمكن التعامل معها.لذلك يجب ألا تصطاد الدروعات إلا إذا كنت واثقا جدا من أنها ستكون استثناءا موجودا بداخله.

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

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

public Integer addNumbers(Integer a, Integer b) {
    Integer c = a + b;          //This will throw a NullPointerException if either 
                                //a or b are set to a null value by the
                                //calling method
    successfulAdditionAlert(c);
    return c;
}

private void successfulAdditionAlert(Integer c) {
    try {
        //Code here to read configurations and send email alerts.
    } catch (Throwable e) {
        //Code to log any exception that occurs during email dispatch
    }
}

يقرأ رمز إرسال تنبيهات البريد الإلكتروني الكثير من تكوينات النظام، وبالتالي قد يكون هناك مجموعة متنوعة من الاستثناءات التي يتم طرحها من مجموعة التعليمات البرمجية هذه.لكننا لا نريد أن ينتشر أي استثناء أثناء إرسال التنبيه إلى أسلوب المتصل، حيث أن هذه الطريقة تهتم ببساطة بمجموع القيمتين الصحيحتين اللتين توفرهما.ومن ثم، يتم وضع رمز إرسال تنبيهات البريد الإلكتروني في ملف try-catch كتلة، حيث Throwable يتم اكتشاف أي استثناءات ويتم تسجيلها فقط، مما يسمح بمواصلة بقية التدفق.

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