java - والنصوص - جافا: فحص مقابل الاستثناء بدون تحديده




قراءة ملف في الجافا (14)

  1. هل يعتبر ما سبق استثناءًا محددًا؟ لا حقيقة أن كنت تقوم بمعالجة استثناء لا يجعله استثناء تم التحقق منه إذا كان RuntimeException.

  2. هل RuntimeException استثناء غير محدد؟ نعم فعلا

تعتبر الاستثناءات التي تم التحقق منها من الفئات الفرعية لـ java.lang.Exception الاستثناءات التي لم يتم التحقق منها عبارة عن فئات فرعية من java.lang.RuntimeException

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

أتمنى أن يساعدك هذا.

س: هل يجب أن أضع استثناءًا دقيقًا أو أخفيه باستخدام استثناء؟

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

try {
     attemptLogin(userCredentials);
} catch (SQLException sqle) {
     throw new LoginFailureException("Cannot login!!"); //<-- Eat away original root cause, thus obscuring underlying problem.
}

بدلا من ذلك القيام بما يلي:

try {
     attemptLogin(userCredentials);
} catch (SQLException sqle) {
     throw new LoginFailureException(sqle); //<-- Wrap original exception to pass on root cause upstairs!.
}

الأكل بعيدا عن السبب الجذري الأصلي يدفن السبب الحقيقي وراء الانتعاش هو كابوس لفرق دعم الإنتاج حيث يتم منحهم جميع الوصول إلى سجلات التطبيق ورسائل الخطأ. على الرغم من أن هذا الأخير هو تصميم أفضل إلا أن العديد من الأشخاص لا يستخدمونه كثيرًا لأن المطورين يفشلون في تمرير الرسالة الأساسية إلى المتصل. لذا ، قم بتدوين ملاحظة ثابتة: Always pass on the actual exception مرة أخرى سواء تم أو لم يتم التفافه في أي استثناء خاص بالتطبيق.

على محاولة اصطياد RuntimeExceptions

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

try {
    setStatusMessage("Hello Mr. " + userObject.getName() + ", Welome to my site!);
} catch (NullPointerException npe) {
   sendError("Sorry, your userObject was null. Please contact customer care.");
}

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

if (userObject != null) {
    setStatusMessage("Hello Mr. " + userObject.getName() + ", Welome to my site!);
} else {
   sendError("Sorry, your userObject was null. Please contact customer care.");
}

ولكن هناك أوقات يكون فيها التحقق من الأخطاء مكلفًا مثل تنسيق الأرقام ، ضع في اعتبارك ذلك -

try {
    String userAge = (String)request.getParameter("age");
    userObject.setAge(Integer.parseInt(strUserAge));
} catch (NumberFormatException npe) {
   sendError("Sorry, Age is supposed to be an Integer. Please try again.");
}

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

لذا NullPointerException و NumberFormatException كلاهما RuntimeExceptions ، يجب أن يستبدل NullPointerException Null-null-check في حين أنصح اصطياد NumberFormatException صراحة لتجنب مقدمة محتملة لخطأ الخطأ.

لقد قرأت العديد من المنشورات على StackOverFlow حول التحقق من مقابل الاستثناءات غير المحددة. أنا بصراحة ما زلت غير متأكد تماما كيفية استخدامها بشكل صحيح.

وقال جوشوا بلوخ في " جاوة الفعالة " ذلك

استخدم الاستثناءات المحددة للظروف القابلة للاسترداد واستثناءات وقت التشغيل لأخطاء البرمجة (البند 58 في الإصدار الثاني)

دعونا نرى ما إذا كنت أفهم هذا بشكل صحيح.

في ما يلي فهمي لاستثناء محدد:

try{
    String userInput = //read in user input
    Long id = Long.parseLong(userInput);
}catch(NumberFormatException e){
    id = 0; //recover the situation by setting the id to 0
}

1. هل يعتبر أعلاه استثناء محدد؟

2. هل يعد RuntimeException استثناء غير محدد؟

في ما يلي فهمي لاستثناء غير محدد:

try{
    File file = new File("my/file/path");
    FileInputStream fis = new FileInputStream(file);   
}catch(FileNotFoundException e){

//3. What should I do here?
    //Should I "throw new FileNotFoundException("File not found");"?
    //Should I log?
    //Or should I System.exit(0);?
}

4. الآن ، لا يمكن أن يكون رمز أعلاه أيضا استثناء محدد؟ يمكنني محاولة استعادة الوضع مثل هذا؟ هل استطيع؟ (ملاحظة: السؤال الثالث الخاص بي هو داخل catch أعلاه)

try{
    String filePath = //read in from user input file path
    File file = new File(filePath);
    FileInputStream fis = new FileInputStream(file);   
}catch(FileNotFoundException e){
    //Kindly prompt the user an error message
    //Somehow ask the user to re-enter the file path.
}

5. لماذا يفعل الناس هذا؟

public void someMethod throws Exception{

}

لماذا يسمحون لهذه الفقاعة الاستثنائية؟ أليس التعامل مع الخطأ في وقت أقرب أفضل؟ لماذا فقاعة؟

تحرير: يجب أن الفقاعة الاستثناء الدقيق أو قناع باستخدام استثناء؟

فيما يلي قراءات بلدي

في Java ، متى يجب أن أقوم بإنشاء استثناء محدد ، ومتى يجب أن يكون استثناء وقت التشغيل؟

متى تختار الاستثناءات المحددة وغير المحددة


1) لا ، NumberFormatException هو استثناء غير محدد. على الرغم من أنك ألقي القبض عليه (أنت غير مطالب) فهو غير محدد. وهذا لأنه فئة فرعية من IllegalArgumentException وهو فئة فرعية من RuntimeException.

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

3/4) يمكنك تنبيه المستخدم بأنهم قاموا باختيار ملف غير موجود وأن يطلبوا ملفًا جديدًا. أو قم فقط بإعلام المستخدم بأنه قام بإدخال شيء غير صالح.

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

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


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

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

دعني اريك مثالا.

دعونا لدينا واجهة جميلة ونظيفة من هذا القبيل

public interface IFoo {
    public void foo();
}

الآن يمكننا كتابة العديد من تطبيقات foo() ، مثل هذه

public class Foo implements IFoo {
    @Override
    public void foo() {
        System.out.println("I don't throw and exception");
    }
}

Class Foo جيد تمامًا. الآن دعونا نجعل المحاولة الأولى في شريط الصف

public class Bar implements IFoo {
    @Override
    public void foo() {
        //I'm using InterruptedExcepton because you probably heard about it somewhere. It's a checked exception. Any checked exception will work the same.
        throw new InterruptedException();
    }
}

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

public class Bar implements IFoo {
    @Override
    public void foo() throws InterruptedException {
        throw new InterruptedException();
    }
}

لن يجمع شريط الصف هذا! لا يلغي أسلوب Bar (foo ()) أسلوب IFoo (foo ()) لأن تواقيعهم مختلفة. يمكنني إزالة التعليق التوضيحي لـOverride ، ولكني أرغب في برمجة ضد واجهة IFoo مثل IFoo foo; ثم قرر بعد ذلك التنفيذ الذي أريد استخدامه ، مثل foo = new Bar(); . إذا لم foo.foo(); طريقة Bar's foo () foo طريقة IFoo ، فعندما أفعل foo.foo(); لن ندعو تنفيذ بار (فو) ().

لتجعل public void foo() throws InterruptedException الفريسة public void foo() Bar public void foo() throws InterruptedException تجاوز public void foo() عفوا public void foo() IFoo public void foo() يجب أن أضيف throws InterruptedException إلى توقيع أسلوب IFoo. هذا ، ومع ذلك ، سوف يسبب مشاكل مع فئة Foo الخاصة بي ، لأن توقيع طريقة foo () يختلف عن توقيع طريقة IFoo. علاوة على ذلك ، إذا أضفت throws InterruptedException إلى foo's foo () سأحصل على خطأ آخر ينص على أن foo 's foo () يعلن أنه يرمي InterruptedException إلا أنه لا يطرح InterruptedException أبداً.

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

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

حل واحد هو التقاط الاستثناء المحدد ، ولفه في استثناء غير محدد وإلقاء الاستثناء غير المحدد.


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

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

لماذا يسمحون لهذه الفقاعة الاستثنائية؟ ليس خطأ في التعامل كلما كان ذلك أفضل؟ لماذا فقاعة؟

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


للإجابة على السؤال الأخير (يبدو أن الآخرين يجيبون بإيجاز أعلاه) ، "هل يجب أن أضع استثناء دقيقًا أو أخفيه باستخدام استثناء؟"

أفترض أنك تعني شيئًا كهذا:

public void myMethod() throws Exception {
    // ... something that throws FileNotFoundException ...
}

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

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


يتم فحص الاستثناءات التي تم فحصها في وقت التجميع بواسطة JVM ومواردها المتعلقة بالموارد (الملفات / db / stream / socket الخ). الدافع للاستثناء المحدد هو أنه في وقت التجميع إذا لم تتوفر الموارد ، يجب أن يحدد التطبيق سلوكًا بديلًا للتعامل مع هذا في كتلة catch / finally.

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

شرح مأخوذ من http://coder2design.com/java-interview-questions/


Checked Exceptions :

  • The exceptions which are checked by the compiler for smooth execution of the program at runtime are called Checked Exception.

  • These occur at compile time.

  • If these are not handled properly, they will give compile time error (Not Exception).
  • All subclasses of Exception class except RuntimeException are Checked Exception.

    Hypothetical Example - Suppose you are leaving your house for the exam, but if you check whether you took your Hall Ticket at home(compile time) then there won't be any problem at Exam Hall(runtime).

Unchecked Exception :

  • The exceptions which are not checked by the compiler are called Unchecked Exceptions.

  • These occur at runtime.

  • If these exceptions are not handled properly, they don't give compile time error. But the program will be terminated prematurely at runtime.

  • All subclasses of RunTimeException and Error are unchecked exceptions.

    Hypothetical Example - Suppose you are in your exam hall but somehow your school had a fire accident (means at runtime) where you can't do anything at that time but precautions can be made before (compile time).


الاستثناءات وقت التشغيل يشار إلى الاستثناءات وقت التشغيل على أنها استثناءات غير محددة. يتم فحص جميع الاستثناءات الأخرى باستثناء ، ولا يتم اشتقاقها من java.lang.RuntimeException.

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

يقوم عدد من الطرق في Java API برمي الاستثناءات المحددة ، لذلك ستكتب غالبًا معالجات الاستثناءات للتعامل مع الاستثناءات التي تم إنشاؤها بطرق لم تكتبها.


All exceptions must be checked exceptions.

  1. Unchecked exceptions are unrestricted gotos. And unrestricted gotos are considered a bad thing.

  2. Unchecked exceptions break encapsulation. To process them correctly, all the functions in the call tree between the thrower and the catcher must be known to avoid bugs.

  3. Exceptions are errors in the function that throws them but not errors in the function that processes them. The purpose of exceptions is to give the program a second chance by deferring the decision of whether it's an error or not to another context. It's only in the other context can the correct decision be made.


All of those are checked exceptions. Unchecked exceptions are subclasses of RuntimeException. The decision is not how to handle them, it's should your code throw them. If you don't want the compiler telling you that you haven't handled an exception then you use an unchecked (subclass of RuntimeException) exception. Those should be saved for situations that you can't recover from, like out of memory errors and the like.



If anybody cares for yet another proof to dislike checked exceptions, see the first few paragraphs of the popular JSON library:

"Although this is a checked exception, it is rarely recoverable. Most callers should simply wrap this exception in an unchecked exception and rethrow: "

So why in the world would anyone make developers keep checking the exception, if we should "simply wrap it" instead? الضحك بصوت مرتفع

http://developer.android.com/reference/org/json/JSONException.html


Just to point out that if you throw a checked exception in a code and the catch is few levels above, you need to declare the exception in the signature of each method between you and the catch. So, encapsulation is broken because all functions in the path of throw must know about details of that exception.


My absolute favorite description of the difference between unchecked and checked exceptions is provided by the Java Tutorial trail article, " Unchecked Exceptions - the Controversy " (sorry to get all elementary on this post - but, hey, the basics are sometimes the best):

Here's the bottom line guideline: If a client can reasonably be expected to recover from an exception, make it a checked exception. If a client cannot do anything to recover from the exception, make it an unchecked exception

The heart of "what type of exception to throw" is semantic (to some degree) and the above quote provides and excellent guideline (hence, I am still blown away by the notion that C# got rid of checked exceptions - particularly as Liskov argues for their usefulness).

The rest then becomes logical: to which exceptions does the compiler expect me to respond, explicitly? The ones from which you expect client to recover.





unchecked-exception