التسلسل الهرمي لفئات الاستثناءات
جزء من قسم Object Oriented Programming في رحلة Java على Coddy — الدرس 59 من 87.
نظام معالجة الاستثناءات في Java مبني على تسلسل هرمي منظم للفئات جذوره في فئة Throwable. يساعدك فهم هذا التسلسل الهرمي على التقاط ومعالجة الاستثناءات بشكل أكثر فعالية.
في القمة يقع Throwable، وهو الأب لجميع الاستثناءات والأخطاء. ولديه فئتان فرعيتان مباشرتان:
Throwable
├── Error // مشاكل خطيرة (لا تقم بالتقاط هذه)
└── Exception // مشاكل يمكن تداركها
└── RuntimeException // استثناءات غير مفحوصةيمثل Error مشكلات خطيرة لا ينبغي للتطبيقات محاولة التعامل معها—مثل OutOfMemoryError أو StackOverflowError. تشير هذه إلى مشكلات أساسية في الـ JVM نفسها.
Exception هو الفرع الذي ستتعامل معه بشكل أكبر. وينقسم إلى فئتين: الاستثناءات المفحوصة (checked exceptions) (فئات فرعية مباشرة من Exception) والاستثناءات غير المفحوصة (unchecked exceptions) (فئات فرعية من RuntimeException).
// فئات الاستثناءات الشائعة
Exception
├── IOException // مشاكل الملفات/الشبكة
├── SQLException // مشاكل قاعدة البيانات
└── RuntimeException
├── NullPointerException
├── ArrayIndexOutOfBoundsException
└── IllegalArgumentExceptionبما أن الاستثناءات هي فئات، فهي تتبع قواعد الوراثة. عندما تقوم بالتقاط نوع استثناء أب، فإنك تلتقط أيضاً جميع أبنائه:
try {
// بعض التعليمات البرمجية
} catch (Exception e) {
// يلتقط جميع الاستثناءات (واسع جداً عادةً)
}try {
// بعض الأكواد
} catch (RuntimeException e) {
// يلتقط فقط استثناءات وقت التشغيل والفئات الفرعية
}يتيح لك هذا التسلسل الهرمي أن تكون دقيقاً أو عاماً حسب الحاجة عند معالجة الأخطاء، وهو الأساس لإنشاء استثناءاتك المخصصة.
التحدي
سهللنقم ببناء محلل استثناءات (exception analyzer) يوضح كيفية عمل التسلسل الهرمي للاستثناءات في Java من الناحية العملية! ستقوم بإنشاء نظام يلتقط الاستثناءات بمستويات مختلفة من التحديد ويبلغ عن النوع الذي تم التقاطه.
ستقوم بتنظيم الكود الخاص بك عبر ثلاثة ملفات:
ExceptionThrower.java: قم بإنشاء فئة (class) يمكنها إطلاق أنواع مختلفة من الاستثناءات بناءً على المدخلات. يجب أن تحتوي الفئة الخاصة بك على ثلاث طرق ثابتة (static methods):triggerRuntime(String type)- بناءً على سلسلة النوع (type string)، قم بإطلاق استثناءات وقت تشغيل (runtime exceptions) مختلفة:- إذا كان النوع هو
"null"، فقم بإطلاقNullPointerExceptionمع الرسالة"Null value encountered" - إذا كان النوع هو
"index"، فقم بإطلاقArrayIndexOutOfBoundsExceptionمع الرسالة"Invalid index" - إذا كان النوع هو
"argument"، فقم بإطلاقIllegalArgumentExceptionمع الرسالة"Bad argument"
triggerArithmetic()- قم بإطلاقArithmeticExceptionمع الرسالة"Division error"triggerGeneric()- قم بإطلاقRuntimeExceptionمع الرسالة"Generic runtime error"- إذا كان النوع هو
ExceptionAnalyzer.java: قم بإنشاء فئة تلتقط الاستثناءات في مستويات هرمية مختلفة وتحدد ما تم التقاطه. قم بتضمين هذه الطرق الثابتة:analyzeSpecific(String type)- استدعِExceptionThrower.triggerRuntime(type)داخل كتلة try. استخدم كتل catch منفصلة لـNullPointerExceptionوArrayIndexOutOfBoundsExceptionوIllegalArgumentException. لكل منها، اطبع:Caught specific: [exception class simple name]متبوعًا بـMessage: [exception message]analyzeWithParent()- استدعِExceptionThrower.triggerArithmetic()داخل كتلة try. التقطه باستخدامRuntimeException(النوع الأب). اطبع:Caught via parent: RuntimeExceptionمتبوعًا بـActual type: [exception class simple name]analyzeWithGrandparent()- استدعِExceptionThrower.triggerGeneric()داخل كتلة try. التقطه باستخدامException(مستوى أعلى في التسلسل الهرمي). اطبع:Caught via grandparent: Exceptionمتبوعًا بـActual type: [exception class simple name]Main.java: اجمع محلل الاستثناءات الخاص بك معًا! ستتلقى مدخلاً واحدًا: سلسلة نوع الاستثناء (إما"null"أو"index"أو"argument").أولاً، اطبع
=== Specific Catch ===واستدعِanalyzeSpecificمع مدخلاتك.ثم اطبع سطرًا فارغًا، و
=== Parent Catch ===، واستدعِanalyzeWithParent.أخيرًا، اطبع سطرًا فارغًا، و
=== Grandparent Catch ===، واستدعِanalyzeWithGrandparent.
ستتلقى مدخلاً واحدًا: نوع الاستثناء الذي سيتم إطلاقه ("null" أو "index" أو "argument").
استخدم e.getClass().getSimpleName() للحصول على اسم فئة الاستثناء و e.getMessage() لاسترداد رسالته. يوضح هذا التحدي كيف أن التقاط نوع استثناء أب يلتقط أيضًا جميع أبنائه - وهو مفهوم أساسي عند تحديد مدى دقة معالجة الاستثناءات الخاصة بك!
ورقة مرجعية
تعتمد معالجة الاستثناءات في Java على تسلسل هرمي للفئات يبدأ من Throwable:
Throwable
├── Error // مشاكل خطيرة (لا تقم بالتقاطها)
└── Exception // مشاكل يمكن تداركها
└── RuntimeException // استثناءات غير مفحوصةتمثل Error مشاكل خطيرة في JVM مثل OutOfMemoryError أو StackOverflowError والتي لا ينبغي للتطبيقات معالجتها.
تنقسم Exception إلى استثناءات مفحوصة (checked exceptions - فئات فرعية مباشرة) واستثناءات غير مفحوصة (unchecked exceptions - فئات فرعية من RuntimeException):
Exception
├── IOException // مشاكل في الملفات/الشبكة
├── SQLException // مشاكل في قاعدة البيانات
└── RuntimeException
├── NullPointerException
├── ArrayIndexOutOfBoundsException
└── IllegalArgumentExceptionالتقاط نوع استثناء أب يؤدي أيضاً إلى التقاط جميع أبنائه:
try {
// some code
} catch (Exception e) {
// يلتقط جميع الاستثناءات
}
try {
// some code
} catch (RuntimeException e) {
// يلتقط فقط استثناءات وقت التشغيل والفئات الفرعية منها
}استخدم e.getClass().getSimpleName() للحصول على اسم فئة الاستثناء و e.getMessage() لاسترداد رسالته.
جرّب بنفسك
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String type = scanner.nextLine();
// TODO: اطبع "=== Specific Catch ===" واستدعِ ExceptionAnalyzer.analyzeSpecific(type)
// TODO: اطبع سطرًا فارغًا، ثم "=== Parent Catch ==="، ثم استدعِ ExceptionAnalyzer.analyzeWithParent()
// TODO: اطبع سطرًا فارغًا، ثم "=== Grandparent Catch ==="، ثم استدعِ ExceptionAnalyzer.analyzeWithGrandparent()
}
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس Object Oriented Programming
1أساسيات الـ OOP
الملفات الخارجيةمقدمة في الـ OOPالفئات (Classes) مقابل الكائنات (Objects)الكلمة المفتاحية thisالدوال (Methods)الحقول (Attributes)دالة البناء (Constructor)تعدد أشكال دالة البناء (Constructor Overloading)مراجعة - آلة حاسبة بسيطة4الوراثة
الوراثة الأساسية (extends)الكلمة المفتاحية superإعادة تعريف الدوال (@Override)تسلسل المنشئات (Constructor Chaining)كلاس Objectالوراثة الأحادية ومتعددة المستوياتلماذا لا توجد وراثة متعددة للكلاساتمراجعة - هيكلية الموظفين7الدوال الخاصة وفئة Object
دالة toString()equals() و hashCode()دالة clone()compareTo() و Comparableواجهة Comparatorمراجعة - الترتيب المخصص10معالجة الاستثناءات في OOP
التسلسل الهرمي لفئات الاستثناءاتالاستثناءات المخصصةالأخطاء من نوع Checked مقابل Uncheckedنمط Try With Resourcesمراجعة - Validated User2محددات الوصول والتغليف
نظرة عامة على مستويات الوصولدوال Getter و Setterإخفاء البياناتالكلمة المفتاحية finalمراجعة - مدير الحساب البنكي5تعدد الأشكال (Polymorphism)
أساسيات الـ Method Overloadingالـ Method Overriding (في وقت التشغيل)الـ Upcasting والـ Downcastingمعامل الـ instanceofالفئات والدوال المجردة (Abstract)مراجعة - حاسبة الأشكال8مفاهيم OOP المتقدمة
الـ Composition مقابل الـ Inheritanceالـ Aggregation مقابل الـ Compositionالفئات الداخلية والمتداخلة والمجهولة (Inner, Nested & Anonymous)الـ Enums ودوالهاالـ Records (Java 16+)الـ Sealed Classes (Java 17+)11أنماط التصميم - الجزء الأول
مقدمة في أنماط التصميمنمط Singletonنمط Factoryنمط Builderنمط Observerنمط Strategy3خصائص الفئة والعضو الساكن
المتغيرات الخاصة بالكائن مقابل المتغيرات الساكنةالدوال الساكنةالكتل البرمجية الساكنةالثوابت (static final)ملخص - العداد والأدوات المساعدة6الواجهات (Interfaces) والأصناف المجردة (Abstract Classes)
مقدمة في الواجهات (Interfaces)تنفيذ الواجهات (Interfaces)تنفيذ واجهات متعددةالـ Default و Static في الواجهاتالأصناف المجردة مقابل الواجهاتالواجهات الوظيفية (Functional Interfaces)مراجعة - نظام الدفع9الأنواع العامة (Generics)
مقدمة في الأنواع العامةالأصناف العامة (Generic Classes)الدوال العامة (Generic Methods)معاملات الأنواع المقيدةالرموز البديلة (?, extends, super)مراجعة - الحاويات العامة12أنماط التصميم - الجزء الثاني
نمط الأمرنمط المحولنمط المزيننمط طريقة القالبنمط الحالةنمط التركيبنمط المكرر