JavaRush /مدونة جافا /Random-AR /الاستثناءات في جافا
Roman
مستوى

الاستثناءات في جافا

نشرت في المجموعة
عندما صادفت موضوع "الاستثناءات"، نشأت العديد من الأسئلة التي كان علي أن أبحث عنها في زوايا مختلفة من الإنترنت لكي أفهم بالتفصيل كيف يعمل كل شيء. ونتيجة لذلك، قمت بتجميع تفسيري الخاص، والذي قد يكون أكثر قابلية للفهم للمبتدئين الذين واجهوا هذه الظاهرة للتو. الاستثناءات في جافا - 1في أجهزة الكمبيوتر، المقاطعة هي إشارة واردة إلى المعالج تفيد بحدوث حدث يتطلب استجابة فورية. تتطلب إشارة المقاطعة من المعالج إيقاف برنامج قيد التشغيل مؤقتًا حتى يمكن مواصلة تشغيله بعد قليل، أي أنه يجب على الكمبيوتر أن يتذكر جميع المعلومات المرتبطة بتنفيذ البرنامج. مثل هذه الانقطاعات مؤقتة، إن لم تكن قاتلة. يمكن أن تحدث مثل هذه الانقطاعات إما عن طريق رمز البرنامج أو عن طريق بعض وظائف الأجهزة (على سبيل المثال، الضغط ببساطة على المفاتيح الموجودة على لوحة المفاتيح، أو أجهزة ضبط الوقت، على سبيل المثال، لإيقاف تشغيل الكمبيوتر تلقائيًا). يقتصر عدد المقاطعات على عدد معين، مدمج في إنتاج معالج معين، أي أنه يتم تخصيص "قنوات" اتصال خاصة لهذا الغرض، مما يسمح لك بالوصول إلى المعالج وتجاوز جميع العمليات الأخرى. يتم أيضًا إنشاء المقاطعات تلقائيًا عند حدوث خطأ في كود البرنامج المنفذ (على سبيل المثال، في حالة حدوث قسمة على صفر). تسمى هذه الانقطاعات تقليديًا بالفخاخ أو الاستثناءات . في مثل هذه الحالات، من المعتاد أن نقول: "تم طرح الاستثناء"، أي تم تشغيل استثناء أو تم طرح استثناء (طرح)، أي طلب مقاطعةمع السؤال "ماذا تفعل؟" أرسلت إلى المعالج. في هذه اللحظة، يتوقف المعالج عن العمل، ويتذكر النقطة التي توقف عندها، أو بالأحرى مجموعة الخلية التالية، التي يجب تنفيذ المعلومات منها. يتم تذكر السلسلة الكاملة للتعليمات المنفذة وغير المنفذة. وبعد ذلك، يقرأ المعالج التعليمات من الذاكرة لاتخاذ الإجراء في حالة حدوث مثل هذا الخطأ. وفقًا لهذه التعليمات، يمكن إدخال قيم جديدة في مجموعات معينة، وإضافة بعض سلاسل الإجراءات أو دورة جديدة (على سبيل المثال، دورة الإرجاع أو التكرار)، وما إلى ذلك، أي اعتمادًا على الخطأ الذي تم وضعه مسبقًا يتم تنفيذ التعليمات لأسفل. يحتوي نظام الكمبيوتر نفسه على العديد من المقاطعات التلقائية المضمنة فيه، والتي يتم تشغيلها بعد فترة زمنية معينة، على سبيل المثال، للتحكم في العمليات الجاري تشغيلها على الكمبيوتر أو تشغيل أجهزة الإنذار المحددة، وجمع الإشارات الخارجية الواردة، ومحولات البيانات المختلفة. تجدر الإشارة إلى أن عددًا كبيرًا من المقاطعات يمكن أن "يعلق" النظام تمامًا لعدد من الأسباب. سيؤدي خطأ في رمز البرنامج تلقائيًا إلى انقطاع المعالج، والذي سيحاول معالجته وفقًا للتعليمات الموضوعة. لكن ليست كل المقاطعات مصممة للتعامل معها، أو قد تؤدي إلى إجراء لا يناسبنا، على سبيل المثال، سيؤدي ذلك ببساطة إلى تعطل التطبيق. لذلك، في البرمجة، من الممكن تنظيم المقاطعة الخاصة بك لقسم معين من التعليمات البرمجية حيث من المحتمل أن يرى المبرمج احتمال حدوث خطأ. في هذه الحالة سيتم معالجة الخطأ داخل البرنامج ولن يتم الاتصال بالمعالج للحصول على تعليمات المعالجة. يتم تنظيم تعريف هذه الكتل عن طريق إنشاء كائن "استثناء" . يتم إنشاء هذا الكائن تلقائيًا في الكتلة try-catch. يتم فحص الكتلة >tryبحثًا عن وجود خطأ، وإذا كان هناك خطأ، ينتقل البرنامج إلى الكتلة catch، حيث يتم اتخاذ الإجراءات لمنع الخطأ أو تسويته. على سبيل المثال، إذا أدخلنا أرقامًا من لوحة المفاتيح ، والتي يجب إضافتها وطرحها لاحقًا، فإن إدخال الحروف من لوحة المفاتيح سيجعل من المستحيل إضافتها بالأرقام (دعنا نشير إلى مجموع هذين المتغيرين بالحرف S). لذلك يجب علينا كفريق tryالتحقق مما إذا كان الرقم A الذي يحتوي على أرقام يمكن إضافته إلى الرقم B الذي يحتوي على حروف (أي S = A + B)، وإذا لم يكن ذلك ممكنا، وهو مستحيل، فتأكد يجب اتخاذ التدابير حتى لا تحدث أخطاء ولا تنتقل مقاطعة جديدة مع السؤال "ماذا تفعل؟" إلى المعالج. إذا لم يكن هناك استثناء في البرنامج، فسيتم مقاطعة تنفيذه من قبل المعالج. إذا كان هناك استثناء، فعندما يتم "اكتشافه" بواسطة الأمر try، ينتقل التحكم إلى الأمر catch، والذي يمكنه تعيين حل بديل، على سبيل المثال، لن نضيف هذين الرقمين، بل نضبط S = A.
int a = 4;
String b = “hello”;
int S = 0;
 try {
   S = a + b;
   int r = 1;
 } catch (Exception igogo1) {
   S = a;
 }
 return S;
/* سلسلة "int r = 1;" لا يتم التنفيذ بسبب حدوث خطأ ويقوم البرنامج بإعادة توجيه العمل مباشرة إلى معالج الاستثناء (catch block*/ وبالتالي فإن وجود الاستثناءات هو فرصة لحل المشكلة داخل البرنامج دون رميها على مستوى المعالج. يحتوي كائن "الاستثناء"، الذي يتم إنشاؤه تلقائيًا في الكتلة tryعند اكتشاف خطأ، على قيمة نوع الخطأ. دعنا نسميها "استثناءنا" - لحالتنا المحددة مع وصف لخطأنا المحدد. أنشأ منشئو لغة Java مسبقًا قائمة معينة من الأخطاء النموذجية والخيارات النموذجية لتصحيحها، أي أنه يوجد في Java مكتبة معينة من الاستثناءات ، والتي يمكننا اللجوء إليها لمعالجة الخطأ الذي حدث، وذلك عدم كتابة كود المعالجة بأنفسنا، وبالتالي فإن OurException على الأرجح قد تم وصفه بالفعل من قبل شخص ما، لذلك نحتاج فقط إلى معرفة اسم أي من هذه الاستثناءات يجب إدراجها في برنامجنا للتعامل مع الكود حيث من المحتمل أن يحدث فشل. إذا ارتكبنا خطأً واخترنا استثناءً غير صحيح من المكتبة ، فلن "يلتقطه" المعالج، ولن يجد الخطأ حلاً داخل البرنامج وسيتم إرسال الطلب إلى المعالج. ولكن هناك طريقة للكسالى. إذا لم نعرف اسم الاستثناء الذي نحتاجه من المكتبة، فيمكننا أن نأخذ العام باسم " الاستثناء "، كما في المثال الموضح أعلاه. هذا الاستثناء قادر على التعامل مع أي نوع من الأخطاء، لكنه غير قادر على توفير معلومات محددة حول الحادث الذي يمكننا تسجيله. تتكون مكتبة الاستثناءات المكتوبة مسبقًا من استثناءات محددة وغير محددة . تلك التي يمكن التحقق منها هي تلك التي يمكن تصحيحها دون مقاطعة عمل البرنامج، أي إذا حاولنا فتح ملف في مجلد غير موجود فيه، فسيقوم النظام بإعلامنا بذلك، ويمكننا إسقاط الملف إلى المجلد المطلوب وتابع البرنامج. أي أنه في الواقع تم إرسال طلب المقاطعة إلى المعالج ، لكن بدون السؤال: "ابحث عما يجب فعله حيال هذه المشكلة؟!؟!" لقد أرسلنا مقاطعة، اكتشفناها بأنفسنا، مع تعليمات جاهزة، قام المعالج بمعالجتها واستمر في تنفيذ البرنامج. لم يتم التحقق من تلك الأخطاء التي لا يمكن تصحيحها وسيتم إغلاق البرنامج قبل الانتهاء، أي أنه سيتم إرسال طلب مقاطعة إلى المعالجوالتي في أي حال من الأحوال سوف يقطع تنفيذ البرنامج. النقطة الوحيدة لكتابة مثل هذه الاستثناءات في البرنامج هي السماح للمستخدم بفهم ما حدث، لأنه بعد اكتشاف هذا الانقطاع، يمكننا عرض رسالة إعلامية على الشاشة، وهذا هو سبب تعطل البرنامج. السبب الثاني لاكتشاف مثل هذه الانقطاعات هو القدرة على تسجيلها في السجلات لتحليلها لاحقًا (لقد تعرضت للاختراق، لكنك على الأقل تعرف مكانها). ونتيجة لوجود مثل هذه المكتبات هي الحاجة إلى تذكر تضمينها. (يمكن العثور على قائمة بالاستثناءات المحددة وغير المحددة مع المكتبات، على سبيل المثال، هنا ) إذا لم نكن نعرف بالضبط المكتبة التي يجب تضمينها أو كان هناك العديد من خيارات الخطأ، فيمكننا catchإدراج الاستثناءات المطلوبة في العديد منها. سيحدد النظام نفسه المعالج الصحيح إذا كان موجودًا في القائمة. بدلاً من استثناء محدد، يمكنك كتابة " استثناء " عام يمكنه التعامل مع أي نوع من الاستثناءات إذا لم تتم معالجته في الكتل السابقة.
int a = 4;
String b = “hello”;
int S = 0;
 try {
   S = a + b;
   int r = 1;
 }
catch(NullPointerException blabla2) {
   System.out.println("Exception handling code for the NullPointerException.");
 }
catch (ArithmeticException ex1) {
   S = a;
 }
catch(Exception uups1) {
   System.out.println("Exception occured");
 }
 return S;
إذا كان هناك كتلة، tryفسيتم إنشاء استثناء تلقائيًا. إذا كنا بحاجة إلى فرض استثناء في وقت ما ، فسيتم استخدام الأمر throw. أي أننا نقوم بإنشاء كائن بشكل مستقل new throw... وبعد ذلك يتوقف البرنامج عن عمله ويرسل طلب مقاطعة إلى المعالج ويتم نقله إلى قسم البرنامج catchحيث يحاول الحصول على تعليمات لمزيد من الإجراءات. من خلال إنشاء الاستثناء يدويًا ، يمكننا تحديد نوعه المحدد من المكتبة:

throw new ArithmeticException("Access denied - You must be at least 18 years old.");
ثم سيقوم المعالج بالبحث عن كتلة catchبهذا الاستثناء المحدد - ابحث في جميع أنحاء البرنامج، من جميع الجوانب catch. بعد throwأمر معالجة الاستثناء، لن يتم تنفيذ كافة التعليمات البرمجية المتبقية للبرنامج، باستثناء ما هو موجود في الكتلة catch. إذا لم يتم العثور على المعالج في البرنامج، فسيتم طرح السؤال على المعالج: "قرر بنفسك ما يجب القيام به" وسيقاطع البرنامج. المكالمة new throw... يمكن إجراؤها داخل >tryوخارج الكتلة (في أي مكان في البرنامج)
try {
   /* функция or действие, в котором есть сомнения. То есть: «попробуй выполнить это, а если не получится, а, если не получится, запускай режим исключения» */
   throw new CallForException(); /* Назначаем исключение, которое будет работать в случае наличия ошибки в функции, описанной выше. Здесь исключение «CallForException» - берется из библиотеки существующих исключений */
} catch (CallForException ee1) {
   /* Корректируем ошибку, чтобы программа не «отвалилась» or выводим сообщение об ошибке or что-то ещё */
} finally {
   /* этот блок работает всегда независимо от того была ошибка or нет. А если была, то сработало ли решение в catch or нет */
   /* часто используется для подчистки хвостов, например, для закрытия запущенного file or базы данных */
   /* в ряде случаев блок catch вообще может быть опущен и оставлен только блок finally и наоборот finally может быть опущен и оставлен только catch */
   /* Не допускается использование этого блока в ряде случаев, например, когда функция System.exit() запущена or другие системные Исключения, типа «отключение электроэнергии» и т.п. */
}

الإخطار بالاستثناءات

قد تتضمن الأساليب التي كتبها شخص ما مسبقًا رمي الاستثناءات. وللاحتياط فقط، حذر المبرمج الذي كتب الكود المبرمجين اللاحقين من احتمال حدوث خطأ في الطريقة التي كتب بها. لذلك، على سبيل المثال، تنص طريقة إنشاء الملف الموضحة أدناه على أنه قد يحدث خطأ عند إنشاء ملف (لا يوجد ملف في المسار المحدد)، مما يعني أنه ستكون هناك حاجة إلى معالج الأخطاء:
public void createFile(String path, String text) throws IOException {
    FileWriter writer = new FileWriter(path, true);
    writer.write(text);
    writer.close();
}
ولكن في الوقت نفسه، لا يوجد معالج نفسه، مما يعني أننا لن نتمكن الآن من استدعاء الطريقة المكتوبة في برنامجنا في الوضع العادي. يجب علينا الآن كتابة معالج الأخطاء واستدعاء هذه الطريقة في الكتلة try:
String filePath = "hello.txt";
String text = "Hello World";

try {
    createFile(filePath, text);
} catch (IOException ex) {
    System.err.println("Error creating file: " + ex);
}

الاستثناءات الأصلية

من الممكن كتابة الاستثناءات الخاصة بك لمعالجة بعض الأخطاء إذا كانت المكتبات الموجودة غير كافية بالنسبة لنا. للقيام بذلك، نقوم ببساطة بإنشاء فئة ترث من فئة الاستثناء
public class StudentNotFoundException extends Exception {

    public StudentNotFoundException (String message) {
        super(message);
    }
}
هناك قاعدتان يجب مراعاتهما عند إنشاء الاستثناءات الخاصة بك:
  1. يجب أن ينتهي اسم صفنا بـ "استثناء"
  2. يجب أن تحتوي الفئة على مُنشئ بمتغير سلسلة يصف تفاصيل مشكلة الاستثناء. في المنشئ، يتم استدعاء المنشئ الفائق ويتم تمرير رسالة.
مثال على استخدام الاستثناء الذي تم إنشاؤه:
public class StudentManager {
    public Student find(String studentID) throws StudentNotFoundException {
        if (studentID.equals("123456")) {
            return new Student();
        } else {
            throw new StudentNotFoundException(
                "Could not find student with ID " + studentID);
        }
    }
}
نلتقط هذا الاستثناء بالكود:
public class StudentTest {
    public static void main(String[] args) {
        StudentManager manager = new StudentManager();
         try {
            Student student = manager.find("0000001");
        } catch (StudentNotFoundException ex) {
            System.err.print(ex);
        }
    }
}
ستكون نتيجة تنفيذ البرنامج: StudentNotFoundException: تعذر العثور على الطالب بالمعرف 0000001

لماذا تحتاج إلى كتابة الاستثناءات؟

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

مراجع:

تعليقات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION