English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
في هذا الدرس، ستعلم كيفية معالجة الاستثناءات باستخدام Java. من أجل معالجة الاستثناءات، سنستخدم block try...catch...finally.
في الدرس السابق، تعرفنا على الاستثناءات. الاستثناء هو حدث غير متوقع يحدث أثناء تنفيذ البرنامج.
في Java، نستخدم مكونات معالجة الاستثناءات try، catch و block finally لمعالجة الاستثناءات.
للقبض على معالجة الاستثناءات، سنقوم بوضع block try...catch...finally حول رمز قد يولد استثناءً. block finally هو اختياري.
القواعد النحوية لـ try...catch...finally هي:
try { // رمز } catch (ExceptionType e) { //block capture } //block finally }
يوضع رمز قد يولد استثناءً داخل block try.
بعد كل block try يجب أن يتبعه block catch أو finally. عند حدوث استثناء، سيتم القبض عليه من قبل block الذي يتبعه.
لا يمكن استخدام block catch بشكل مستقل، يجب أن يتبعه block try.
class Main { public static void main(String[] args) { try { int divideByZero = 5 / 0; System.out.println("الكود المتبقي في حزمة try"); } System.out.println("ArithmeticException => " + e.getMessage()); } } }
نتائج الإخراج
ArithmeticException => / by zero
في هذا المثال
نحن نقسم الرقم إلى صفر في حزمة try. هذا ينتج استثناء ArithmeticException.
عندما يحدث استثناء، يقوم البرنامج بتخطي باقي الكود في حزمة try.
في هذا المكان، قمنا بإنشاء حزمة catch لمعالجة استثناء ArithmeticException. لذلك، يتم تنفيذ الجمل في حزمة catch.
إذا لم يكن أي جملة في حزمة try قد أحدثت استثناءً فسيتم السكوت عن كود الحزمة من catch.
للمجلس الأولي يمكن أن يكون هناك حزمة واحدة أو أكثر من catch.
نوع المعامل في كل حزمة catch يشير إلى نوع الاستثناء الذي يمكن معالجته. تسمح الحزم المتعددة بمعالجة كل استثناء بطريقة مختلفة.
class ListOfNumbers { public int[] arrayOfNumbers = new int[10]; public void writeList() { try { arrayOfNumbers[10] = 11; } System.out.println("NumberFormatException => " + e1.getMessage()); } System.out.println("IndexOutOfBoundsException => " + e2.getMessage()); } } } class Main { public static void main(String[] args) { ListOfNumbers list = new ListOfNumbers(); list.writeList(); } }
نتائج الإخراج
IndexOutOfBoundsException => البدالة 10 خارج الحدود بالنسبة للطول 10
في هذا المثال، نحن نعلن عن مصفوفة صغيرة الحجم من النوع int تسمى arrayOfNumbers.
نحن نعرف أن عدد البدائل يبدأ دائمًا من 0. لذلك، عندما نحاول تخصيص قيمة للبدالة 10، يحدث استثناء IndexOutOfBoundsException لأن نطاق عدد البدائل هو من 0 إلى 9.
عندما يحدث استثناء في حزمة try
الاستثناء يتم رميها إلى الحزمة الأولى من catch. الحزمة الأولى من catch لا تعالج استثناء IndexOutOfBoundsException، لذلك يتم تمريرها إلى الحزمة التالية من catch.
حزمة catch الثانية في المثال أعلاه هي معالجة استثناء مناسبة لأنها تتعامل مع استثناء IndexOutOfBoundsException. لذلك، تم تنفيذها.
للمجلس الأولي فقط يمكن أن يكون هناك حزمة واحدة من try.
جملة finally اختيارية. ولكن إذا تم تعريفها، فإنها ستُنفذ دائمًا (حتى لو لم يحدث استثناء).
إذا حدث استثناء، يتم تنفيذها بعد جملة try...catch. وإذا لم يحدث استثناء، يتم تنفيذها بعد جملة try.
النحو الأساسي للجملة finally هو:
try { //code } //جملة catch } //جملة catch } //جملة finally تستمر في التنفيذ }
class Main { public static void main(String[] args) { try { int divideByZero = 5 / 0; } System.out.println("ArithmeticException => " + e.getMessage()); } System.out.println("جملة finally دائمًا ما تنفذ"); } } }
نتائج الإخراج
ArithmeticException => / by zero جملة finally دائمًا ما تنفذ
في هذا المثال، سنقوم بتقسيم الرقم على الصفر. مما يؤدي إلى إطلاق استثناء ArithmeticException يتم القبض عليه في جملة catch، وستنفذ جملة finally دائمًا
استخدام جملة finally يُعتبر ممارسة جيدة. لأنها تحتوي على كود تنظيف مهم، مثل
قد يتم تجاوز الكود المكتوب باستخدام جملة return أو continue أو break بشكل غير متوقع
إغلاق الملف أو الاتصال
لقد ذكرنا أن finally دائمًا ما تنفذ، وعادة ما يكون مثل هذا. ولكن، في بعض الحالات، لا تنفذ جملة finally:
استخدام طريقة System.exit()
حدث استثناء في جملة finally
السطر يُتوقف
لنأخذ مثالاً، نحاول استخدام FileWriter لإنشاء ملف جديد ونكتب البيانات باستخدام PrintWriter.
import java.io.*; class ListOfNumbers { private int[] list = new int[10]; public ListOfNumbers() { //في مصفوفة القائمة تُخزن القيم الصحيحة for (int i = 0; i < 10; i++) { list[i] = i; } } } public void writeList() { PrintWriter out = null; try { System.out.println("دخول جملة try"); //إنشاء ملف جديد OutputFile.txt out = new PrintWriter(new FileWriter("OutputFile.txt")); //كتابة القيم من مصفوفة القائمة إلى ملف جديد تم إنشاؤه for (int i = 0; i < 10; i++) { out.println("قيمة في: " + i + " = " + list[i]); } } System.out.println("IndexOutOfBoundsException => " + e1.getMessage()); } System.out.println("IOException => " + e2.getMessage()); } //تحقق من أن PrintWriter مفتوح if (out != null) { System.out.println("إغلاق PrintWriter"); out.close(); } else { System.out.println("لا يمكن فتح PrintWriter"); } } } } class Main { public static void main(String[] args) { ListOfNumbers list = new ListOfNumbers(); list.writeList(); } }
عند تشغيل هذا البرنامج، قد تحدث إحدى الاثنتين:
حدث استثناء في جملة try
تنفيذ جملة try بشكل طبيعي
قد يحدث استثناء عند إنشاء FileWriter جديد. إذا لم يتم إنشاء أو كتابة الملف المحدد، فإنه يتم رمي IOException.
عندما يحدث استثناء، سنحصل على الناتج التالي.
دخول جملة try IOException => OutputFile.txt لا يمكن فتح PrintWriter
عندما لا يحدث استثناء وينجح تنفيذ جملة try بشكل طبيعي، سنحصل على الناتج التالي.
دخول جملة try إغلاق PrintWriter
سيتم إنشاء ملف OutputFile.txt، ويشمل ما يلي
قيمة في: 0 = 0 قيمة في: 1 = 1 قيمة في: 2 = 2 قيمة في: 3 = 3 قيمة في: 4 = 4 القيمة في الموضع: 5 = 5 القيمة في الموضع: 6 = 6 القيمة في الموضع: 7 = 7 القيمة في الموضع: 8 = 8 القيمة في الموضع: 9 = 9
دعونا نحاول أن نفهم بشكل أفضل عملية معالجة الاستثناءات باستخدام المساعدة في المثال السابق.
توضح الصورة أعلاه مسار تنفيذ البرنامج عند حدوث استثناء أثناء إنشاء FileWriter.
لإيجاد الطريقة التي حدث فيها الاستثناء، يدعو النظام إلى طريقة writeList()، والتي تدعو بدورها إلى طريقة FileWriter() لإنشاء ملف OutputFile.txt جديد.
عند حدوث استثناء، يخطئ النظام في التغاضي عن باقي الكود في قالب try.
يبدأ النظام في البحث بالعكس في قائمة التسمية للعثور على معالج استثناء مناسب.
في هذا المكان، لا يوجد معالج استثناء لFileWriter، لذا سينفذ النظام بشكل تلقائي إلى الطريقة التالية في قائمة التسمية، وهي writeList.
يحتوي طريقة writeList على معالجين استثناء: معالج لIndexOutOfBoundsException، ومعالج آخر لIOException.
ثم، سيتعامل النظام بشكل متتابع مع هذه المعالجات.
في هذا المثال، المعالج الأول يتعامل مع IndexOutOfBoundsException. هذا لا يتطابق مع IOException التي أُثيرت في قالب try.
لذلك، سيتم التحقق مما إذا كان التالي هو معالج IOException. إذا كان نوع الاستثناء المطلق مطابقاً، سيتم تنفيذ الكود في قالب catch المماثل.
بعد تنفيذ معالج الاستثناءات، سيتم تنفيذ قالب finally.
في هذا السيناريو، لأن حدث استثناء في FileWriter، لم يتم فتح كائن PrintWriter object out، لذا لا يتطلب الإغلاق.
الآن، لنفترض أن لم يحدث أي استثناء أثناء تشغيل هذا البرنامج، وأن قالب try تم تنفيذه بشكل صحيح. في هذه الحالة، سيتم إنشاء ملف OutputFile.txt وسيتم كتابته.
من المعروف أن تنفيذ قالب finally لا يتعلق بمعالجة الاستثناءات. لأن لم يكن هناك استثناء، تم فتح PrintWriter ويتعين إغلاقه. يتم ذلك عن طريق جملة out.close() في قالب finally.
من بداية Java SE 7 وما فوق، يمكننا الآن استخدام قالب catch واحد لالتقاط أكثر من نوع استثناء.
بهذا يمكن تقليل تكرار الكود وزيادة بسيطته وإنتاجيته.
يمكن استخدام رمز الثلاثي الفاصلة (|) لفصل كل نوع استثناء يمكن معالجته من قبل قالب catch.
جملة try-with-resources هي جملة try تحتوي على إعلان مصادر واحدة أو أكثر.
try { // code catch (ExceptionType1 | Exceptiontype2 ex) { // قالب catch }
للحصول على معلومات إضافية، يرجى زيارةJava تحديد استثناءات متعددة.
جملة try-with-resources هي جملة try تحتوي على إعلان مصادر واحدة أو أكثر.
جملة try-with-resources هي جملة try تحتوي على إعلان مصادر واحدة أو أكثر.
try (تعريف المصدر) { // استعمال المصدر catch (ExceptionType e1) { // قالب catch }
الموارد هي الأشياء التي يجب إغلاقها عند انتهاء البرنامج. يجب إعلانها وتحديدها داخل جملة try.
دعونا نأخذ مثالاً.
try (PrintWriter out = new PrintWriter(new FileWriter("OutputFile.txt"))) { // استعمال المصدر }
جملة try-with-resources تُسمى أيضًاإدارة الموارد التلقائية. يتم إغلاق جميع الموارد تلقائيًا في نهاية الجملة.
للحصول على معلومات إضافية، يرجى زيارةجملة try-with-resources Java.