أفضل الممارسات في إدارة الاستثناءات في جافا أو C# [مغلقة]

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

سؤال

أنا عالقة اتخاذ قرار بشأن كيفية التعامل مع استثناءات في التطبيق.

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

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

هنا بعض التعليمات البرمجية (JAVA) من أسلوب نموذجي)

public boolean doSomething(Object p_somthingToDoOn)
{
    boolean result = false;

    try{
        // if dirty object then clean
        doactualStuffOnObject(p_jsonObject);

        //assume success (no exception thrown)
        result = true;
    }
    catch(Exception Ex)
    {
        //don't care about exceptions
        Ex.printStackTrace();
    }
    return result;
}

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

في ملخص أسئلة رئيسية:

  1. هل يمكن أن مجرد التقاط استثناءات ولكن ليس فقاعة لهم أو رسميا إعلام النظام (إما عن طريق تسجيل أو إخطار المستخدم) ؟
  2. ما أفضل الممارسات هناك استثناءات لا يؤدي في كل شيء يتطلب حاول/catch?

متابعة/تحرير

شكرا لجميع ردود الفعل وجدت بعض مصادر ممتازة على إدارة الاستثناءات على الانترنت:

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

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

أيضا, هذه هي جميلة خيار التعليق من m3rLinEz.

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

من هذا التعليق أنه يجلب بعض الأسئلة للتفكير عند التعامل مع الاستثناءات:

  • ما فائدة هذا الاستثناء القيت ؟
  • كيف يعقل أن التعامل معها ؟
  • هل المتصل يهتمون حقا استثناء أو أنها لا تهتم فقط إذا كان الاتصال ناجحا ؟
  • هو إجبار الطالب إلى إدارة احتمال استثناء مرح ؟
  • أنت محترمة idoms من اللغة ؟
    • هل تحتاج حقا إلى العودة علامة نجاح مثل منطقية?العودة منطقية (أو الباحث) هو أكثر من ج عقلية من جافا (Java أنت فقط التعامل مع الاستثناء) واحد.
    • اتبع خطأ إدارة يبني المرتبطة اللغة :) !
هل كانت مفيدة؟

المحلول

يبدو غريبا بالنسبة لي أن كنت تريد للقبض على استثناءات وتحويلها إلى رموز الخطأ.لماذا تعتقد المتصل تفضل رموز الخطأ على استثناءات عندما يكون هذا الأخير هو الافتراضي في كل من Java و C# ؟

أما عن أسئلتك:

  1. يجب أن قبض فقط الاستثناءات التي يمكنك التعامل مع الواقع.فقط اصطياد الاستثناءات ليست الشيء الصحيح القيام به في معظم الحالات.هناك بعض الاستثناءات (مثلتسجيل و تنظيم استثناءات بين المواضيع) ولكن حتى في تلك الحالات يجب عليك عموما rethrow الاستثناءات.
  2. بالتأكيد يجب أن لا يكون لديك الكثير من حاول/catch البيانات الخاصة بك التعليمات البرمجية.مرة أخرى, فكرة هو فقط قبض الاستثناءات يمكنك التعامل معها.قد تشمل أعلى استثناء معالج لتحويل أي غير معالج الاستثناءات في شيء إلى حد ما مفيدة للمستخدم النهائي ولكن وإلا يجب أن لا محاولة للقبض على كل استثناء في في كل مكان ممكن.

نصائح أخرى

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

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

في استخدام القواعد التالية:

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

أجد البرمجية التالية إلى أن رائحة:

try
{
    //do something
}
catch(Exception)
{
   throw;
}

التعليمات البرمجية مثل هذا لا يخدم أي نقطة لا ينبغي أن تدرج.

وأود أن يوصي مصدر جيد آخر في هذا الموضوع.إنها مقابلة مع المخترعين من C# و Java, أندرس هيلسبرغ و جيمس جوسلينج على التوالي في موضوع جافا فحص استثناء.

فشل والاستثناءات

وهناك أيضا موارد كبيرة في الجزء السفلي من الصفحة.

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

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

أندرس هيلسبرغ:دعونا نبدأ مع الإصدارات ، لأن القضايا من السهل جدا أن نرى هناك.دعونا نقول أنا إنشاء أسلوب فو أن يعلن ذلك يلقي الاستثناءات A و B و C.في الإصدار الثاني من فو ، أريد أن أضيف مجموعة من الميزات و الآن فو قد رمي استثناء D.وهو كسر تغيير بالنسبة لي أن أضيف د أن يلقي شرط أن الأسلوب, لأن المتصل الموجودة من هذا الأسلوب يكاد يكون من المؤكد لا تحمل ذلك الاستثناء.

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

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

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

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

تحرير:إضافة المزيد من التفاصيل عن converstaion

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

كما القواعد من الإبهام ، معالجة الاستثناء ينبغي أن يكون شيئا حول هذه المبادئ التوجيهية في أي ترتيب معين:

  • أجل الصيانة دائما تسجيل استثناءات بحيث عندما تبدأ في رؤية الحشرات السجل سوف تساعد في الإشارة إلى المكان الخاص بك علة المرجح أن تكون قد بدأت.لا تترك printStackTrace() أو أمثال ذلك ، هناك احتمالات أحد المستخدمين سوف تحصل على واحد من هذه تتبعات المكدس في نهاية المطاف ، بالضبط صفر المعرفة ما يجب القيام به مع ذلك.
  • قبض الاستثناءات يمكنك التعامل, فقط هؤلاء ، والتعامل معها, لا مجرد رمي لهم المكدس.
  • دائما قبض معين استثناء فئة, و عموما يجب أن لا قبض نوع Exception, أنت من المحتمل جدا أن ابتلاع وإلا استثناءات مهمة.
  • أبدا (أبدا) الصيد Errors!!, بمعنى: لا تمسك Throwables كما Errors هي فرعية من هذا الأخير. Errors هي المشاكل التي على الأرجح لن تكون قادرة على التعامل مع (مثلا ، OutOfMemory, أو غيرها من JVM المسائل)

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

يجب عليك التقاط فقط الاستثناءات يمكنك التعامل معه.على سبيل المثال, إذا كنت تتعامل مع القراءة عبر شبكة الاتصال مرات وتحصل على استثناء يمكنك المحاولة مرة أخرى.ومع ذلك إذا كنت تقرأ عبر الشبكة والحصول على IndexOutOfBounds استثناء ، كنت حقا لا يمكن أن تحمل هذا لأنك لا (حسنا, في هذه الحالة لن) أعلم ما سبب ذلك.إذا كنت تريد الذهاب إلى return false أو -1 أو null, تأكد من انها محددة استثناءات.أنا لا أريد مكتبة أنا باستخدام عودته كاذبة على شبكة قراءة عند الاستثناء الذي تم كومة من الذاكرة.

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

Ex.

try
{
   sendMessage();

   if(message == success)
   {
       doStuff();
   }
   else if(message == failed)
   {
       throw;
   }
}
catch(Exception)
{
    logAndRecover();
}

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

كل ما سبق يبدو من المعقول ، وغالبا ما يكون مكان العمل الخاص بك قد يكون لها سياسة.في المكان الذي يجب تعريف أنواع الاستثناء: SystemException (لحالها) ، ApplicationException (فحص).

واتفقنا على أن SystemExceptions من غير المرجح أن تكون قابلة للاسترداد و سوف bve التعامل معها مرة واحدة في الأعلى.إلى تقديم مزيد من السياق ، SystemExceptions هي exteneded للإشارة إلى مكان ارتكابها ، على سبيل المثال RepositoryException, ServiceEception, ، وما إلى ذلك.

ApplicationExceptions يمكن أن يكون معنى مثل الأعمال InsufficientFundsException و يجب أن يتم التعامل معها من قبل رمز العميل.

Witohut مثال ملموس, من الصعب التعليق على التنفيذ ولكن لن تستخدم عودة رموز, أنهم مسألة صيانة.قد تبتلع استثناء ، ولكن عليك أن تقرر لماذا دائما تسجيل الحدث stacktrace.وأخيرا ، طريقة أخرى لمعالجة الأمر إلى حد ما زائدة (باستثناء التغليف?), لذلك doactualStuffOnObject(p_jsonObject); يمكن العودة منطقية!

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

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

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

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

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

الحالات حيث TryXXXX المنطقي عندما يتم لف الطرف الثالث وظيفة أن يلقي في الحالات التي ليست استثنائية حقا ، أو بسيطة من الصعب اختبار دون استدعاء الدالة.على سبيل المثال سيكون شيئا مثل:

// throws NumberNotHexidecimalException
int ParseHexidecimal(string numberToParse); 

bool TryParseHexidecimal(string numberToParse, out int parsedInt)
{
     try
     {
         parsedInt = ParseHexidecimal(numberToParse);
         return true;
     }
     catch(NumberNotHexidecimalException ex)
     {
         parsedInt = 0;
         return false;
     }
     catch(Exception ex)
     {
         // Implement the error policy for unexpected exceptions:
         // log a callstack, assert if a debugger is attached etc.
         LogRetailAssert(ex);
         // rethrow the exception
         // The downside is that a JIT debugger will have the next
         // line as the place that threw the exception, rather than
         // the original location further down the stack.
         throw;
         // A better practice is to use an exception filter here.
         // see the link to Exception Filter Inject above
         // http://code.msdn.microsoft.com/ExceptionFilterInjct
     }
}

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

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

على سبيل المثال جافا.لانغ.تعكس.مجموعة لديها ثابت set الطريقة:

static void set(Object array, int index, Object value);

ج الطريقة سيكون

static int set(Object array, int index, Object value);

...مع قيمة الإرجاع يجري نجاح المؤشر.ولكن أنت لست في C العالم أي أكثر من ذلك.

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

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

إذا كنت تريد الذهاب إلى الصيد استثناء return false ، يجب أن تكون محددة للغاية استثناء.أنت لا تفعل ذلك أنت اصطياد كل منهم وإعادة كاذبة.إذا كنت تحصل على MyCarIsOnFireException أريد أن أعرف عن ذلك الحق بعيدا!بقية الاستثناءات قد لا يهتمون.لذلك يجب أن يكون كومة من معالجات الاستثناء أن يقول "قف قف هناك شيئا خطأ هنا" بعض الاستثناءات (rethrow أو الصيد rethrow جديد الاستثناء الذي يشرح أفضل ما حدث) و return false للآخرين.

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

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

بلدي استراتيجية:

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

إذا كانت وظيفة يجب أن تعود شيئا ثم عندما استثناء/خطأ العودة null, وإلا لرد البند.

بدلا من منطقي a سلسلة ويمكن إرجاع تحتوي على وصف الخطأ.

في كل قضية قبل أن يعود أي شيء سجل الخطأ.

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

حاول/catch شكل كتل مجموعة ثانية من المنطق جزءا لا يتجزأ من أكثر من الأولى (الرئيسية) مجموعة ، كما أنها وسيلة رائعة على الجنيه من غير مقروءة, من الصعب تصحيح التعليمات البرمجية السباغيتي.

لا تزال تستخدم على نحو معقول أنها تعمل العجائب في القراءة, ولكن عليك أن تتبع اثنين من القواعد البسيطة:

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

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

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

بول.

قد أتأخر قليلا في الإجابة لكن معالجة الخطأ هو شيء يمكننا دائما أن تتغير وتتطور على طول الوقت.إذا كنت ترغب في قراءة شيء أكثر حول هذا الموضوع كتبت في ما بعد في بلدي بلوق جديدة حول هذا الموضوع. http://taoofdevelopment.wordpress.com

سعيد الترميز.

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