CodeGym /مدونة جافا /Random-AR /الاستثناءات: محددة وغير محددة ومخصصة
John Squirrels
مستوى
San Francisco

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

نشرت في المجموعة
أهلاً! في الدرس الأخير، تعرفنا على الاستثناءات في لغة جافا، ورأينا أمثلة على كيفية العمل معها. اليوم سنلقي نظرة أعمق على بنية الاستثناءات، ونتعلم كيفية كتابة الاستثناءات الخاصة بنا :)

أنواع الاستثناءات

كما قلنا سابقًا، هناك الكثير من الاستثناءات في Java، ما يقرب من 400! ولكنها جميعها مقسمة إلى مجموعات، لذلك من السهل تذكرها إلى حد ما. هكذا تبدو: الاستثناءات: محددة وغير محددة ومخصصة - 2 جميع الاستثناءات لها سلف مشترك في الفصل Throwable. يتم اشتقاق مجموعتين رئيسيتين منه: الاستثناءات ( الاستثناء ) والأخطاء ( الخطأ ). خطأ - يمثل هذا خطأً فادحًا في وقت التشغيل يتعلق بتشغيل جهاز Java الظاهري. في معظم الحالات، لا يلزم معالجة الخطأ، لأنه يشير إلى بعض العيوب الخطيرة في التعليمات البرمجية. أشهر هذه الأخطاء هي StackOverflowError (يحدث هذا، على سبيل المثال، عندما تستدعي إحدى الطرق نفسها إلى ما لا نهاية) و OutOfMemoryError (يحدث هذا عندما لا تكون هناك ذاكرة كافية لإنشاء كائنات جديدة). كما ترون، في هذه المواقف، عادةً لا يوجد أي شيء يمكن التعامل معه على الإطلاق في وقت التشغيل: الكود ببساطة مكتوب بشكل غير صحيح ويحتاج إلى إعادة صياغته. استثناء - يمثل هذا استثناءً: موقف استثنائي غير مخطط له يحدث أثناء تشغيل البرنامج. إنها ليست خطيرة مثل الخطأ، لكنها لا تزال تتطلب اهتمامنا. تنقسم جميع الاستثناءات إلى نوعين: محددة وغير محددة . الاستثناءات: محددة وغير محددة ومخصصة - 3 كافة الاستثناءات المحددة مشتقة من Exceptionالفئة. ماذا يعني "فحص"؟ لقد أشرنا إلى ذلك في الدرس الأخير: "وبالتالي فإن مترجم Java يعرف الاستثناءات الأكثر شيوعًا والمواقف التي قد تحدث فيها." على سبيل المثال، يعرف أنه إذا كان الكود يقرأ البيانات من ملف، فقد لا يكون الملف موجودًا بسهولة. وهناك الكثير من مثل هذه المواقف (التي يمكن استنتاجها). وبناءً على ذلك، يقوم المترجم بالتحقق من الكود الخاص بنا مسبقًا للتأكد من وجود هذه الاستثناءات المحتملة. إذا عثر عليها، فلن تقوم بتجميع الكود حتى نتعامل معها أو نعيد طرحها. النوع الثاني من الاستثناء هو "غير محدد". وهي مشتقة من RuntimeExceptionالطبقة. كيف تختلف عن الاستثناءات المحددة؟ يبدو أن هناك أيضًا الكثير من الفئات المختلفة المشتقة من RuntimeException(والتي تصف استثناءات وقت التشغيل). والفرق هو أن المترجم لا يتوقع هذه الأخطاء. يبدو أنه يقول: "عندما تمت كتابة الكود، لم أجد أي شيء مريب، ولكن حدث خطأ ما أثناء تشغيله. من الواضح أن هناك أخطاء في الكود!" وبالفعل هذا صحيح. غالبًا ما تكون الاستثناءات التي لم يتم التحقق منها نتيجة لأخطاء المبرمج. ومن الواضح أن المترجم لا يستطيع توقع كل المواقف السيئة المحتملة التي قد يخلقها الناس بأيديهم. :) ولذلك، فهو لا يتحقق مما إذا كان قد تم التعامل مع هذه الاستثناءات في الكود الخاص بنا. لقد واجهت بالفعل العديد من الاستثناءات التي لم يتم التحقق منها:
  • يحدث استثناء حسابي عند القسمة على صفر
  • يحدث ArrayIndexOutOfBoundsException عند محاولة الوصول إلى موضع خارج المصفوفة.
بالطبع، يمكنك أن تتخيل أن منشئي Java قد أدخلوا معالجة الاستثناءات الإلزامية، ولكن في هذه الحالة سيكون الكود معقدًا للغاية. في أي عملية قسمة، هل سيتعين عليك كتابة try-catchقالب للتحقق مما إذا كنت قد قسمت على صفر عن طريق الخطأ؟ في أي وقت تقوم فيه بالوصول إلى مصفوفة، سيتعين عليك كتابة كتلة try-catchللتحقق مما إذا كان الفهرس الخاص بك خارج الحدود. سيكون كل شيء بمثابة رمز معكرونة وسيكون غير قابل للقراءة تمامًا. ومن المنطقي أن يتم التخلي عن هذه الفكرة. ونتيجة لذلك، لا يلزم معالجة الاستثناءات التي لم يتم التحقق منها في try-catchكتل أو إعادة طرحها (على الرغم من أن هذا ممكن تقنيًا، كما هو الحال مع الخطأ).

كيفية رمي الاستثناء الخاص بك

بالطبع، لا يستطيع منشئو Java التنبؤ بكل موقف استثنائي قد ينشأ في البرامج. هناك الكثير من البرامج في العالم، وهي متنوعة للغاية. لكن هذا لا يدعو للقلق، لأنه يمكنك إنشاء الاستثناء الخاص بك، إذا لزم الأمر. هذا من السهل جدا القيام به. كل ما عليك فعله هو إنشاء صفك الخاص. يجب عليك التأكد من أن اسمه ينتهي بـ "استثناء". لا يتطلب المترجم هذا، لكن المبرمجين الآخرين الذين يقرأون الكود الخاص بك سوف يفهمون على الفور أنها فئة استثناء. بالإضافة إلى ذلك، قم بالإشارة إلى أن الفصل موروث من Exceptionالفصل (يتطلب المترجم ذلك). على سبيل المثال، لنفترض أن لدينا Dogفئة. يمكننا أن نمشي الكلب باستخدام هذه walk()الطريقة. ولكن قبل القيام بذلك، نحتاج إلى التحقق مما إذا كان حيواننا الأليف يرتدي طوقًا ومقودًا وكمامة. إذا كان أي من هذه المعدات مفقودًا، فإننا نطرح الاستثناء الخاص بنا: DogIsNotReadyException . رمزه يبدو مثل هذا:
public class DogIsNotReadyException extends Exception {

   public DogIsNotReadyException(String message) {
       super(message);
   }
}
للإشارة إلى أن الفئة استثناء، تحتاج إلى كتابة " extension Exception " بعد اسم الفئة (وهذا يعني "الفئة مشتقة من فئة الاستثناء"). في المُنشئ، نقوم ببساطة باستدعاء مُنشئ الفئة برسالةException سلسلة (في حالة حدوث استثناء، سنعرض الرسالة ووصف الخطأ للمستخدم). إليك كيف يبدو هذا في رمز الفصل الخاص بنا:
public class Dog {

   String name;
   boolean isCollarPutOn;
   boolean isLeashPutOn;
   boolean isMuzzlePutOn;


   public Dog(String name) {
       this.name = name;
   }

   public static void main(String[] args) {

   }

   public void putCollar() {

       System.out.println("The collar is on!");
       this.isCollarPutOn = true;
   }

   public void putLeash() {

       System.out.println("The leash is on!");
       this.isLeashPutOn = true;
   }

   public void putMuzzle() {
       System.out.println("The muzzle is on!");
       this.isMuzzlePutOn = true;
   }

   public void walk() throws DogIsNotReadyException {

   System.out.println("We're getting ready for a walk!");
   if (isCollarPutOn && isLeashPutOn && isMuzzlePutOn) {
       System.out.println("Hooray, let's go for a walk! " + name + " is very happy!");
   } else {
       throw new DogIsNotReadyException(name + " is not ready for a walk! Check the gear!");
   }
 }

}
الآن walk()تطرح طريقتنا DogIsNotReadyException . ويتم ذلك باستخدام الكلمة الرئيسية رمي. كما قلنا سابقًا، الاستثناء هو كائن. لذا، عندما يحدث استثناء (يفتقد الكلب شيئًا ما) في طريقتنا، فإننا نقوم بإنشاء DogIsNotReadyExceptionكائن جديد ونرميه باستخدام الكلمة الأساسية throw. نضيف " throws DogIsNotReadyException " إلى إعلان الطريقة. بمعنى آخر، يدرك المترجم الآن أن استدعاء الطريقة walk()قد يتحول إلى حالة استثنائية. وبناء على ذلك، يجب معالجة هذا الاستثناء إذا قمنا باستدعاء هذه الطريقة في مكان ما في برنامجنا. دعونا نحاول القيام بذلك بالطريقة main():
public static void main(String[] args) {

   Dog dog = new Dog("Buddy");
   dog.putCollar();
   dog.putMuzzle();
   dog.walk();// Unhandled exception: DogIsNotReadyException
}
لن يتم تجميع هذا. لا يتم التعامل مع الاستثناء! نقوم بلف الكود الخاص بنا في try-catchكتلة للتعامل مع الاستثناء:
public static void main(String[] args) {

   Dog dog = new Dog("Buddy");
   dog.putCollar();
   dog.putMuzzle();
   try {
       dog.walk();
   } catch (DogIsNotReadyException e) {
       System.out.println(e.getMessage());
       System.out.println("Checking the gear! Is the collar on? " + dog.isCollarPutOn + "\r\n Is the leash on? "
       + dog.isLeashPutOn + "\r\n Is the muzzle on? " + dog.isMuzzlePutOn);
   }
}
الآن دعونا نلقي نظرة على إخراج وحدة التحكم: الياقة قيد التشغيل! كمامة على! نحن نستعد للنزهة! الأصدقاء غير مستعدين للنزهة! تحقق من العتاد! فحص العتاد! هل الياقة موجودة؟ صحيح هل المقود قيد التشغيل؟ كاذبة هل الكمامة على؟ صحيح انظر إلى مدى إفادة مخرجات وحدة التحكم! نحن نرى كل خطوة يتم اتخاذها في البرنامج؛ نرى مكان حدوث الخطأ، ويمكننا أيضًا أن نرى على الفور ما يفتقده كلبنا بالضبط. :) وهذه هي الطريقة التي تقوم بها بإنشاء الاستثناءات الخاصة بك. كما ترون، لا يوجد شيء معقد في هذا الأمر. وعلى الرغم من أن منشئي Java لم يكلفوا أنفسهم عناء تضمين استثناء خاص للكلاب سيئة التجهيز في اللغة، فقد أصلحنا خطأهم. :)
تعليقات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION