هو في النهاية كتلة من دون كتلة catch a java مكافحة النمط ؟

StackOverflow https://stackoverflow.com/questions/601152

سؤال

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

try {
   doSomeStuff()
   doMore()
} finally {
   doSomeOtherStuff()
}

المشكلة كان من الصعب استكشاف لأن doSomeStuff() رمى استثناء ، والتي بدورها تسبب doSomeOtherStuff() أيضا رمي استثناء.أما الاستثناء الثاني (القيت من قبل كتلة أخيرا) ألقيت إلى رمز ، ولكن لم يكن لها مقبض على الاستثناء الأول (ألقيت من doSomeStuff ()) ، الذي كان الجذر الحقيقي-سبب المشكلة.

إذا كان رمز قد قال هذا بدلا من ذلك, المشكلة كانت بادية للعيان:

try {
    doSomeStuff()
    doMore()
} catch (Exception e) {
    log.error(e);
} finally {
   doSomeOtherStuff()
}

لذا سؤالي هو:

هو في النهاية كتلة استخدامها دون أي catch المعروفة جافا مكافحة النمط ؟ (يبدو بالتأكيد أن يكون لا-بسهولة-على ما يبدو فرعية من الواضح المعروفة لمكافحة نمط "لا تلتهم استثناءات!")

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

المحلول

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

نصائح أخرى

وأعتقد الحقيقي "نموذج مضاد" هنا تفعل شيئا في كتلة finally التي يمكن رمي، وليس عدم وجود الصيد.

وليس على الإطلاق.

ما هو الخطأ هو رمز داخل أخيرا.

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

وعلى الاطلاق لا بأس محاولة مع أي الصيد أخيرا و. مراعاة ما يلي:

InputStream in = null;
try {
    in = new FileInputStream("file.txt");
    // Do something that causes an IOException to be thrown
} finally {
    if (in != null) {
         try {
             in.close();
         } catch (IOException e) {
             // Nothing we can do.
         }
    }
}

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

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

شيء واحد أنا لا عند التعامل مع الملف مقابض (الكتابة) هو تدفق تيار من قبل إغلاقه باستخدام IOUtils.closeQuietly الأسلوب الذي لا يلقي الاستثناءات:


OutputStream os = null;
OutputStreamWriter wos = null;
try { 
   os = new FileOutputStream(...);
   wos = new OutputStreamWriter(os);
   // Lots of code

   wos.flush();
   os.flush();
finally {
   IOUtils.closeQuietly(wos);
   IOUtils.closeQuietly(os);
}

أنا أحب هذه الطريقة للأسباب التالية:

  • انها ليست آمنة تماما تجاهل استثناء عند إغلاق الملف - إذا كانت هناك وحدات البايت التي لم تكن مكتوبة إلى ملف بعد ملف قد لا يكون في الدولة المتصل تتوقعها ؛
  • حتى لو يتم رفع استثناء خلال طريقة دافق () ، وسوف يتم نشرها إلى المتصل ولكن لا يزال سوف تأكد من أن جميع الملفات المغلقة.طريقة IOUtils.closeQuietly(...) أقل مطول ثم محاولة المقابلة ...قبض ...تجاهلي كتلة ؛
  • إذا باستخدام إخراج متعددة تيارات النظام عن طريقة دافق() هو المهم.الجداول التي تم إنشاؤها عن طريق تمرير تيارات أخرى كما منشئات يجب مسح الأول.نفس الشيء يسري على close() الأسلوب ، ولكن دافق() هو أكثر وضوحا في رأيي.

وانا اقول كتلة حاول دون كتلة الصيد هو نموذج مضاد. قائلا: "لم يكن لديك أخيرا دون الصيد" هو مجموعة فرعية من "لا يكون المحاولة دون الصيد".

وأنا استخدم حاول / أخيرا في الشكل التالي:

try{
   Connection connection = ConnectionManager.openConnection();
   try{
       //work with the connection;
   }finally{
       if(connection != null){
          connection.close();           
       }
   }
}catch(ConnectionException connectionException){
   //handle connection exception;
}

وأنا أفضل ذلك إلى محاولة / صيد / النهاية (+ متداخلة حاول / catch في النهاية). أعتقد أنه من أكثر إيجازا، وأنا لا تكرار الصيد (استثناء).

try {
    doSomeStuff()
    doMore()
} catch (Exception e) {
    log.error(e);
} finally {
   doSomeOtherStuff()
}

لا تفعل ذلك إما ... كنت مجرد اختبأ المزيد من البق (وأيضا لا أخفى لهم بالضبط ... ولكن جعل من الصعب التعامل معها، وعندما تصاب استثناء كنت اصطياد أيضا أي نوع من RuntimeException (مثل NullPointer وArrayIndexOutOfBounds).

في عام، وقبض على استثناءات لديك للقبض على (محددة الاستثناءات) والتعامل مع الآخرين في وقت الاختبار. تم تصميم RuntimeExceptions لاستخدامها في أخطاء مبرمج - والأخطاء مبرمج والأشياء التي لا ينبغي أن يحدث في برنامج تصحيحه بشكل صحيح

في رأيي، هو أكثر في القضية التي finally مع catch تشير بعض النوع من المشاكل. المصطلح الموارد بسيط جدا:

acquire
try {
    use
} finally {
    release
}

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

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

لذلك، مجردة التعامل مع بعيدا مع تنفيذ حوالي لغة. مصدرك

وحاول / وأخيرا هو وسيلة لتحرير الموارد بشكل صحيح. التعليمات البرمجية في كتلة وأخيرا يجب NEVER رمي أنه ينبغي أن تعمل فقط على الموارد أو الدولة التي تم الحصول عليها قبل دخول كتلة المحاولة.

وبوصفها جانبا، وأعتقد أن log4J هو تقريبا مضاد للنمط.

وإذا كنت ترغب في فحص برنامج RUNNING استخدام التفتيش PROPER TOOL (أي مصحح، IDE، أو بالمعنى المدقع ويفر رمز بايت ولكن لا تضع البيانات LOGGING في كل الأسطر القليلة!).

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

وtry-finally قد تساعدك على خفض كود النسخ واللصق في حالة وسيلة لديها بيانات return متعددة. النظر في المثال التالي (الروبوت جافا):

boolean doSomethingIfTableNotEmpty(SQLiteDatabase db) {
    Cursor cursor = db.rawQuery("SELECT * FROM table", null);
    if (cursor != null) { 
        try {
            if (cursor.getCount() == 0) { 
                return false;
            }
        } finally {
            // this will get executed even if return was executed above
            cursor.close();
        }
    }
    // database had rows, so do something...
    return true;
}

إذا لم يكن هناك شرط finally، قد يكون لديك لكتابة cursor.close() مرتين: قبل return false وأيضا بعد شرط if المحيطة

أعتقد أن نحاول مع أي الصيد هو النموذج المضاد.استخدام try/catch للتعامل مع استثنائية الشروط (ملف IO أخطاء المهلة مأخذ ، إلخ) ليس مضاد نمط.

إذا كنت تستخدم حاول/أخيرا على تنظيف, النظر في استخدام كتلة بدلا من ذلك.

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