هل من أي وقت مضى لا يمسك استثناء ، أو رمي استثناء لن تكون اشتعلت ؟

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

سؤال

لقد تعاملت مع الحالات التي أود أن رمي/rethrow استثناء مع العلم أن رمز المحيطة بها سوف الصيد المحددة استثناء.ولكن هل هناك أي وقت كنت ترغب في رمي استثناء ، مع العلم أنه لن يتم القبض عليه ؟

أو على الأقل لا يمسك استثناء ؟

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

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

المحلول

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

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

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

  • هل تستخدم الاستثناءات كبديل حقيقي تسجيل? هناك تقريبا لا سبب للقيام بذلك ؛ تنظر الحقيقي تسجيل آلية بدلا من ذلك.قبض على استثناء و يكون مسجل معرفة ما حدث.

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

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

نصائح أخرى

هناك قاعدة جيدة جدا التي صادفت قبل فترة:

رمي استثناء عندما الأسلوب لا يمكن أن تفعل ما يقول اسمها يفعل.

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

قاعدة أخرى يجب اتباعها وهي:

لا يمسك استثناء إلا إذا كنت تعرف ما تريد القيام به مع ذلك.

ومن الواضح أن عليك أن تتضمن رمز تنظيف في محاولة...وأخيرا كتلة ولكن يجب أن لا مجرد التقاط استثناء من أجل اللحاق به.و يجب أن لا تبتلع الاستثناءات بصمت.في حين أن هناك مناسبات عندما قد تحتاج للقبض على جميع الاستثناءات (مثلبفعل الصيد (Exception ex) في C#) هذه غير المألوف إلى حد ما عموما جدا تقنية محددة السبب.على سبيل المثال ، عند استخدام مؤشرات الترابط .الصافي 2.0 أو في وقت لاحق ، إذا كان استثناء يهرب من الخيط الخاص بك ، سوف يسبب التطبيق بالكامل المجال لتفريغ.في هذه الحالات, ومع ذلك-على أقل تقدير-يجب تسجيل تفاصيل الاستثناء خطأ وتقديم تفسير في التعليقات.

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

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

لذا أقترح أن تسأل بدلا من ذلك: "متى يجب الإمساك استثناء؟"

وبالتأكيد. على سبيل المثال، إذا كنت تحاول تحميل بعض بايت إلى سلسلة في جاوة:

try {
  String myString = new String(byteArray, "UTF-8");
} catch (UnsupportedEncodingException e) {
  // Platform doesn't support UTF-8?  What is this, 1991?
  throw new RuntimeExceptione(e);
}

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

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

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

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

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

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

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

ولكن هل هناك أي وقت كنت ترغب في رمي استثناء ، مع العلم أنه لن يتم القبض عليه ؟

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

أن تكون عادلة ، أعتقد أن يعتمد في جزء منه على هذا النوع من البرمجة تفعله و أحيانا نفس مبرمج ينتهي بناء كل من المكتبة البرمجية التي تستهلك قال المكتبة.

هل من أي وقت مضى لا يمسك استثناء ؟

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

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

أنها ممارسة شائعة 'رمي/rethrow' استثناء إذا قبض الاستثناء في المستوى حيث لا يمكن التعامل معها.ولكن كنت دائما تقريبا إضافة السياق إلى مسألة على الأقل إضافة بعض قطع الأشجار على مستوى أعلى أن نقول أنه تم القبض rethrown.

على سبيل المثال

وهو يدعو B C (يلقي استثناء)

ب المصيد/rethrows

على المصيد.

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

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

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

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

تحرير

إذا كنت تكتب مكتبة, عليك أن تختار وقت مبكر إذا كانت وظيفة الخاص بك سوف رمي استثناء ، أو يكون استثناء آمنة.في تلك الحالات, في بعض الأحيان سوف رمي استثناء وليس لدي أي فكرة إذا كان حزب الدعوة قبض عليه.ولكن في هذه الحالة ، اصطياد ليست مسؤوليتك ، طالما api تعلن أن وظيفة يمكن أن رمي استثناءات.(أنا أبحث عن الكلمة التي تعني 'يمكن أن رمي استثناء'...أحد يعرف ما هو ؟ انها سوف علة لي كل يوم.)

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

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

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

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

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

وثانيا، يجب أن بطرح استثناء مع العلم لن يتم القبض عليه؟ أعتقد أن السؤال يسيء فهم طبيعة الطرق التي يعاد استخدامها. الفكرة كلها من طريقة هو أن لديها "عقد" أنه يلي: أنها تقبل بعض المعلمات وإرجاع قيمة معينة، بالإضافة إلى أنه أيضا يلقي بعض الاستثناءات في ظل ظروف معينة. هذا العقد - والامر متروك للطالب ما يفعلونه معها. بالنسبة لبعض المتصلين، باستثناء A قد تشير إلى وجود حالة قابلة للاسترداد. للمتصلين آخرين، فإنه قد تشير إلى وجود خلل. ومن ما قلته أعلاه، يجب أن يكون واضحا أنه إذا يدل على وجود خلل استثناء، <م> يجب أن لا يتم القبض .

وإذا كنت أتساءل ماذا يعني هذا ل استثناء مايكروسوفت المشاريع المكتبة التعامل مع كتلة : نعم، انها مكسورة جدا. يقولون لك catch (Exception x) ثم يقرر ما إذا كان rethrow على أساس سياسة الخاص بك؛ بعد فوات الأوان - الكتل finally أعدمت بالفعل تلك النقطة. لا تفعل ذلك.

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

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

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

وهذا يعتمد على ما تعنيه ب "الوقوع". شيء ما، في مكان ما أدرك في نهاية المطاف استثناء سواء كانت OS الأساسي أو أي شيء آخر.

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

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

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

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

إذا كنت كتابة التعليمات البرمجية API، أو رمز الإطار أنك لن تستخدم نفسك، ثم لديك أي فكرة ما إذا كان شخص سيصابون الاستثناءات.

نعم، انها الفرصة الوحيدة لي لصفعة المطور استهلاك الخدمة / وجوه لنقول لهم "أور dO1n أنه من الخطأ !!!!".

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

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

و

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

و

النظام لا (بعد) تعرف كيفية إصلاح التناقض و استرداد بأمان

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

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

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

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

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

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

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