معالجة الأخطاء في Java: try/catch والتقنيات المتقدمة

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

مقدمة: لماذا تعتبر معالجة الأخطاء في Java فنًا

\n

معالجة الأخطاء في Java ليست مجرد آلية لمنع انهيار البرنامج. إنها أداة لتصميم بنية موثوقة وقابلة للقراءة ويمكن التنبؤ بها. كل مطور على دراية ببنية try/catch، ولكن على المستوى المتقدم، من المهم فهم الفروق الدقيقة: متى تستخدم الاستثناءات المُفحَصة، وكيفية إغلاق الموارد بشكل صحيح، ولماذا يمكن لـ multi-catch أن ينقذك من تكرار الكود. في هذه المقالة، سنستعرض التقنيات المتقدمة للعمل مع الاستثناءات في Java والتي ستساعدك على كتابة كود أكثر نظافة وأمانًا.

\n\n

1. Multi-catch ودمج الاستثناءات

\n

قبل Java 7، كانت معالجة أنواع مختلفة من الاستثناءات في كتلة catch واحدة مستحيلة. كان عليك إما تكرار الكود أو استخدام فئة أصل مشتركة (مثل Exception)، مما يقلل من دقة معلومات الخطأ. مع ظهور multi-catch، تغير الوضع.

\n

صيغة multi-catch

\n

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

\n
try {\n    // كود قد يرمي FileNotFoundException أو IOException\n    FileReader reader = new FileReader("file.txt");\n    int data = reader.read();\n} catch (FileNotFoundException | IOException e) {\n    System.err.println("خطأ في الإدخال/الإخراج: " + e.getMessage());\n}
\n

هام: المتغير e في هذه الكتلة هو final (أو effectively final). هذا يعني أنه لا يمكن إعادة تعيينه، ولكن يمكن استدعاء طرق الفئة الفائقة المشتركة (مثل getMessage()).

\n

متى تستخدم multi-catch؟

\n
    \n
  • إذا كانت الاستثناءات غير مرتبطة هرميًا (مثل IOException و SQLException).
  • \n
  • إذا كان منطق المعالجة متطابقًا تمامًا.
  • \n
  • إذا كنت تريد تجنب تكرار كتل catch.
  • \n
\n\n

2. Try-with-resources: الإدارة التلقائية للموارد

\n

أحد أكثر الأخطاء شيوعًا في Java هو نسيان إغلاق مورد (ملف، مأخذ توصيل، اتصال بقاعدة بيانات). الإغلاق اليدوي في كتلة finally يؤدي إلى كود ضخم وخطر تسرب الموارد. بنية try-with-resources (Java 7+) تحل هذه المشكلة.

\n

كيف يعمل

\n

يجب أن يقوم المورد بتنفيذ واجهة AutoCloseable (أو Closeable). بعد انتهاء كتلة try (أو عند حدوث استثناء)، سيتم إغلاق المورد تلقائيًا.

\n
try (FileReader reader = new FileReader("file.txt");\n     BufferedReader br = new BufferedReader(reader)) {\n    String line = br.readLine();\n    System.out.println(line);\n} catch (IOException e) {\n    System.err.println("خطأ: " + e.getMessage());\n}\n// reader و br تم إغلاقهما تلقائيًا
\n

إمكانيات متقدمة

\n
    \n
  • موارد متعددة: يمكن الإعلان عنها مفصولة بفاصلة منقوطة. يتم الإغلاق بترتيب عكسي.
  • \n
  • الاستثناءات المكبوتة: إذا تم طرح استثناء أثناء إغلاق المورد، وكان الاستثناء الرئيسي قد تم طرحه بالفعل، تقوم Java "بكبت" استثناء الإغلاق. يمكن الحصول عليه عبر طريقة getSuppressed().
  • \n
  • الاستخدام مع الموارد المخصصة: أي فئة تنفذ AutoCloseable يمكن استخدامها في try-with-resources.
  • \n
\n\n

3. إنشاء استثناءات مخصصة وأفضل الممارسات

\n

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

\n

الاستثناءات المُفحَصة مقابل غير المُفحَصة

\n

اتبع قاعدة بسيطة: إذا كان من الممكن معالجة الاستثناء من قبل العميل (مثل تنسيق إدخال غير صحيح)، فاجعله مُفحَصًا (يرث من Exception). إذا كان خطأ في البرمجة لا يمكن التعافي منه (مثل مؤشر فارغ)، فاجعله غير مُفحَص (يرث من RuntimeException).

المدونات

توصيات الكتب