توفر جافا نهجًا قويًا وموجهًا للكائنات للتعامل مع سيناريوهات الاستثناء المعروفة باسم معالجة الاستثناء في جافا. قبل فترة قصيرة، كتبت مقالًا طويلًا عن معالجة الاستثناء في جافا واليوم أقوم بسرد بعض الأسئلة المهمة حول استثناءات جافا مع الإجابات لمساعدتك في المقابلات.
- ما هو الاستثناء في جافا؟
- ما هي الكلمات الرئيسية لمعالجة الاستثناءات في جافا؟
- شرح تسلسل استثناءات جافا؟
- ما هي الأساليب الهامة في فئة استثناء جافا؟
- شرح ميزة ARM في جافا 7 وكتلة الامساك المتعددة؟
- ما الفرق بين الاستثناءات المدروسة وغير المدروسة في جافا؟
- ما الفرق بين الكلمات throw وthrows في جافا؟
- كيفية كتابة استثناءات مخصصة في جافا؟
- ما هو خطأ “خارج الذاكرة” في جافا؟
- ما هي السيناريوهات المختلفة التي تتسبب في “استثناء في خيط الرئيسي”؟
- ما الفرق بين final وfinally وfinalize في جافا؟
- ماذا يحدث عندما يتم طرح استثناء بواسطة الطريقة الرئيسية؟
- هل يمكننا أن نملك كتلة اصطياد فارغة؟
- قدم بعض ممارسات معالجة الاستثناءات في جافا؟
- ما هي المشكلة في البرامج أدناه وكيف يمكننا إصلاحها؟
1. ما هو استثناء في جافا؟
الاستثناء هو حدث خطأ يمكن أن يحدث أثناء تنفيذ برنامج ويعطل تدفقه العادي. يمكن أن ينشأ الاستثناء من أنواع مختلفة من الحالات مثل إدخال بيانات خاطئة من قبل المستخدم، فشل الأجهزة، فشل اتصال الشبكة، إلخ. كلما حدث أي خطأ أثناء تنفيذ جملة جافا، يتم إنشاء كائن استثناء، ثم يحاول محرك تشغيل جافا العثور على معالج استثناء لمعالجة الاستثناء. إذا تم العثور على معالج استثناء مناسب، يتم تمرير كائن الاستثناء إلى كود المعالج لمعالجة الاستثناء، المعروف بـ اصطياد الاستثناء. إذا لم يتم العثور على معالج، يقوم التطبيق بإلقاء الاستثناء إلى البيئة التشغيلية ويقوم محرك التشغيل جافا بإنهاء البرنامج. يُستخدم إطار معالجة الاستثناء في جافا للتعامل مع أخطاء التشغيل فقط، حيث لا يتم التعامل مع أخطاء الوقت التجميعي من خلال إطار معالجة الاستثناء.
2. ما هي الكلمات الرئيسية لمعالجة الاستثناءات في جافا؟
هناك أربع كلمات رئيسية تستخدم في معالجة الاستثناءات في جافا.
- throw: في بعض الأحيان نريد بشكل صريح إنشاء كائن استثناء ومن ثم رميه لإيقاف المعالجة العادية للبرنامج. تستخدم كلمة المفتاح throw لرمي الاستثناءات إلى التشغيل ليتعامل معها.
- throws: عندما نقوم برمي أي استثناء مدقق في طريقة ولا نتعامل معه، فإننا بحاجة إلى استخدام كلمة المفتاح throws في توقيع الطريقة لتعلم البرنامج المستدعي الاستثناءات التي قد يتم رميها بواسطة الطريقة. يمكن أن تتعامل الطريقة المستدعية مع هذه الاستثناءات أو نقلها إلى طريقة مستدعيها باستخدام كلمة المفتاح
throws
. يمكننا توفير استثناءات متعددة في جملة الـ throws ويمكن استخدامها مع الطريقة main() أيضًا. - try-catch: نستخدم كتلة try-catch لمعالجة الاستثناءات في كودنا. try هو بداية الكتلة و catch هو في نهاية كتلة try للتعامل مع الاستثناءات. يمكن أن يكون لدينا عدة كتل catch مع try ويمكن أن تكون كتل try-catch متداخلة أيضًا. تتطلب كتلة catch معلمًا يجب أن يكون من نوع Exception.
- أخيرًا: يعد الكتلة finally اختيارية ويمكن استخدامها فقط مع كتلة try-catch. نظرًا لأن الاستثناء يوقف عملية التنفيذ، قد نكون قد فتحنا بعض الموارد التي لن تُغلق، لذا يمكننا استخدام كتلة finally. تُنفذ كتلة finally دائمًا، سواء حدث استثناء أم لا.
3. شرح تسلسل الاستثناء في جافا؟
الاستثناءات في جافا هي تسلسلية، وتُستخدم التوريث لتصنيف أنواع مختلفة من الاستثناءات. Throwable
هو الفئة الأم في تسلسل استثناءات جافا، ولها ابنتان – Error
و Exception
. الاستثناءات مقسمة بشكل أدق إلى استثناءات مفحوصة واستثناءات تشغيلية. الأخطاء هي حالات استثنائية تكون خارج نطاق التطبيق ولا يمكن توقعها أو استردادها، مثل فشل الأجهزة، وتعطل جافا في إجراءات التشغيل، أو خطأ في الذاكرة. الاستثناءات المفحوصة هي حالات استثنائية يمكن توقعها في البرنامج ومحاولة استردادها منها، على سبيل المثال، FileNotFoundException. يجب أن نُمسك بهذا الاستثناء ونقدم رسالة مفيدة للمستخدم ونسجله بشكل صحيح لأغراض التصحيح. Exception
هي الفئة الأم لجميع الاستثناءات المفحوصة. استثناءات التشغيل يتسبب بها برمجة سيئة، على سبيل المثال، محاولة استرجاع عنصر من المصفوفة. يجب علينا التحقق من طول المصفوفة أولاً قبل محاولة استرجاع العنصر، وإلا فقد يُثير الاستثناء ArrayIndexOutOfBoundException
أثناء التشغيل. RuntimeException
هي الفئة الأم لجميع استثناءات التشغيل.
ما هي الأساليب المهمة لفئة Java Exception؟
الاستثناء وجميع فئاته الفرعية لا تقدم أي أساليب محددة ويتم تعريف جميع الأساليب في الفئة الأساسية Throwable.
- String getMessage() – تقوم هذه الطريقة بإرجاع سلسلة الرسالة لـ Throwable ويمكن توفير الرسالة أثناء إنشاء الاستثناء من خلال بنائه.
- String getLocalizedMessage() – تم توفير هذه الطريقة بحيث يمكن للفئات الفرعية استبدالها لتوفير رسائل محلية محددة للموقع للبرنامج الذي يستدعيها. تستخدم تنفيذ الفئة Throwable لهذه الطريقة ببساطة طريقة
getMessage()
لإرجاع رسالة الاستثناء. - synchronized Throwable getCause() – تقوم هذه الطريقة بإرجاع سبب الاستثناء أو قيمة null إذا كان السبب غير معروف.
- String toString() – تقوم هذه الطريقة بإرجاع معلومات حول Throwable بتنسيق سلسلة، تحتوي السلسلة المُرجَعَة على اسم فئة Throwable ورسالة محلية.
- void printStackTrace() – تقوم هذه الطريقة بطباعة معلومات تتبع الكومة إلى تدفق الخطأ القياسي، تم تحميل هذه الطريقة بشكل زائد ويمكننا تمرير PrintStream أو PrintWriter كوسيط إضافي لكتابة معلومات تتبع الكومة إلى ملف أو تدفق.
5. شرح ميزة ARM في جافا 7 وكتلة الامساك المتعددة؟
إذا كنت تقوم بالتقاط الكثير من الاستثناءات في كتلة try واحدة، فستلاحظ أن كود كتلة الامساك يبدو بشكل سيء للغاية ويتكون في الغالب من كود مكرر لتسجيل الخطأ، مع الأخذ في الاعتبار أحد الميزات التي جاءت مع جافا 7 وهي كتلة الامساك المتعددة حيث يمكننا الامساك بعدة استثناءات في كتلة واحدة من الامساك. تبدو كتلة الامساك مع هذه الميزة كما يلي:
catch(IOException | SQLException | Exception ex){
logger.error(ex);
throw new MyException(ex.getMessage());
}
في معظم الأحيان، نستخدم كتلة finally فقط لإغلاق الموارد وأحيانًا ننسى إغلاقها ونحصل على استثناءات في وقت التشغيل عندما تنفد الموارد. هذه الاستثناءات صعبة التصحيح وقد نحتاج إلى النظر في كل مكان نستخدم فيه نوعًا من المورد للتأكد من إغلاقه. لذلك كانت إحدى التحسينات في جافا 7 هي محاولة مع الموارد حيث يمكننا إنشاء مورد في بيان try ذاته واستخدامه داخل كتلة try-catch. عندما تخرج التنفيذ من كتلة try-catch، يُغلق البيئة التنفيذية تلك الموارد تلقائيًا. عينة لكتلة try-catch مع هذا التحسين هي:
try (MyResource mr = new MyResource()) {
System.out.println("MyResource created in try-with-resources");
} catch (Exception e) {
e.printStackTrace();
}
اقرأ المزيد عن هذا في Java 7 ARM.
6. ما هي الفرق بين الاستثناءات المدققة والاستثناءات غير المدققة في جافا؟
- يجب التعامل مع الاستثناءات المدققة في الكود باستخدام كتلة try-catch، أو يجب على الأقل أن تستخدم الطريقة الكلمة المفتاحية throws لإعلام المتصل بالاستثناءات المدققة التي قد يتم رميها من الطريقة. الاستثناءات غير المدققة ليست مطلوبة للتعامل معها في البرنامج أو ذكرها في جملة throws للطريقة.
Exception
هو الفئة الأساسية لجميع الاستثناءات المدققة بينماRuntimeException
هي الفئة الأساسية لجميع الاستثناءات غير المدققة. يجب ملاحظة أن RuntimeException هي فئة فرعية من Exception.- الاستثناءات المدققة هي حالات الخطأ التي يتطلب التعامل معها في الكود، وإلا ستحصل على خطأ في وقت الترجمة. على سبيل المثال، إذا استخدمت FileReader لقراءة ملف، فإنه يقوم برمي
FileNotFoundException
ويجب أن نلتقطه في كتلة try-catch أو نقوم برميه مرة أخرى إلى الطريقة المتصلة. الاستثناءات غير المدققة يتسبب فيها البرمجة السيئة في معظم الأحيان، على سبيل المثال، NullPointerException عند استدعاء طريقة على مرجع كائن دون التأكد من أنه غير معلوم. على سبيل المثال، يمكنني كتابة طريقة لإزالة جميع الحروف الصوتية من السلسلة. من مسؤولية المتصل التأكد من عدم تمرير سلسلة فارغة. قد أقوم بتغيير الطريقة للتعامل مع هذه السيناريوهات ولكن في الواقع، ينبغي على المتصل أن يتولى هذا الأمر.
7. ما الفرق بين الكلمتين throw و throws في لغة الجافا؟
الكلمة throws تُستخدم مع توقيع الطريقة لتعلن عن الاستثناءات التي قد تُلقيها الطريقة بينما تُستخدم كلمة throw لتعطيل تدفق البرنامج وتسليم كائن الاستثناء إلى وقت التشغيل للتعامل معه.
8. كيفية كتابة استثناءات مخصصة في لغة الجافا؟
يمكننا تمديد فئة Exception
أو أي من فئاتها الفرعية لإنشاء فئة استثناء مخصصة لنا. يمكن أن تحتوي فئة الاستثناء المخصصة على متغيرات وطرق خاصة بها يمكننا استخدامها لتمرير رموز الخطأ أو معلومات الاستثناء الأخرى إلى معالج الاستثناء. يُظهر المثال البسيط أدناه كيفية إنشاء استثناء مخصص.
package com.journaldev.exceptions;
import java.io.IOException;
public class MyException extends IOException {
private static final long serialVersionUID = 4664456874499611218L;
private String errorCode="Unknown_Exception";
public MyException(String message, String errorCode){
super(message);
this.errorCode=errorCode;
}
public String getErrorCode(){
return this.errorCode;
}
}
9. ما هو OutOfMemoryError في لغة الجافا؟
الخطأ في الذاكرة الخارجة (OutOfMemoryError) في جافا هو فئة فرعية من java.lang.VirtualMachineError ويتم طرحه بواسطة JVM عندما ينفد ذاكرة العلم. يمكننا إصلاح هذا الخطأ عن طريق توفير المزيد من الذاكرة لتشغيل تطبيق جافا من خلال خيارات الجافا. $>java MyProgram -Xms1024m -Xmx1024m -XX:PermSize=64M -XX:MaxPermSize=256m
10. ما هي السيناريوهات المختلفة التي تسبب “Exception in thread main”؟
بعض السيناريوهات الشائعة لاستثناء الخطوط الرئيسية هي:
- استثناء في خط الرئيسي java.lang.UnsupportedClassVersionError: يحدث هذا الاستثناء عندما يتم تجميع فئة جافا من إصدار JDK آخر وتحاول تشغيلها من إصدار جافا آخر.
- استثناء في خط الرئيسي java.lang.NoClassDefFoundError: هناك نوعان من هذا الاستثناء. النوع الأول هو عندما تقدم الاسم الكامل للفئة مع امتداد .class. السيناريو الثاني هو عندما لا يتم العثور على الفئة.
- استثناء في خط الرئيسي java.lang.NoSuchMethodError: main: يحدث هذا الاستثناء عندما تحاول تشغيل فئة ليس لديها الطريقة الرئيسية.
- استثناء في الخيط الرئيسي java.lang.ArithmeticException: كلما تم طرح استثناء من الطريقة الرئيسية، يتم طباعة الاستثناء في وحدة التحكم. الجزء الأول يشرح أن استثناءً يتم طرحه من الطريقة الرئيسية، الجزء الثاني يطبع اسم فئة الاستثناء ثم بعد نقطتين يطبع رسالة الاستثناء.
اقرأ المزيد حول هذه المسائل في Java Exception in thread main.
11. ما الفرق بين final و finally و finalize في جافا؟
final و finally هم كلمات مفتاحية في جافا بينما finalize هو طريقة. يمكن استخدام الكلمة النهائية مع متغيرات الف
ماذا يحدث عندما يتم رمي استثناء بواسطة الطريقة الرئيسية؟
عندما يتم رمي استثناء بواسطة الطريقة الرئيسية، يقوم Java Runtime بإنهاء البرنامج وطباعة رسالة الاستثناء وتتبع الكدمات في وحدة التحكم النظامية.
13. هل يمكننا أن نملك كتلة استثناء فارغة؟
نعم يمكننا أن نملك كتلة استثناء فارغة ولكنها مثال على سوء البرمجة. يجب ألا نمتلك أبدًا كتلة استثناء فارغة لأنه إذا تم اصطياد الاستثناء بواسطتها، فلن يكون لدينا أي معلومات حول الاستثناء وسيكون من الصعب جدًا تصحيحه. يجب أن يكون هناك على الأقل عبارة تسجيل لتسجيل تفاصيل الاستثناء في وحدة التحكم أو ملفات السجل.
14. قدم بعض ممارسات معالجة الاستثناء في جافا؟
بعض أفضل الممارسات المتعلقة بمعالجة الاستثناء في جافا هي:
- استخدم استثناءات محددة لسهولة التصحيح.
- رمي الاستثناءات مبكرًا (الفشل بسرعة) في البرنامج.
- امسك الاستثناءات في وقت متأخر في البرنامج، واسمح للمتصل بالتعامل مع الاستثناء.
- استخدم ميزة ARM في Java 7 للتأكد من إغلاق الموارد أو استخدم كتلة finally لإغلاقها بشكل صحيح.
- سجل دائمًا رسائل الاستثناء لأغراض التصحيح.
- استخدم كتلة multi-catch لإغلاق أنظف.
- استخدم استثناءات مخصصة لرمي نوع واحد من الاستثناء من واجهة برمجة التطبيقات الخاصة بك.
- اتبع التعليمات في التسمية، وانته دائمًا بكلمة Exception.
- وثق الاستثناءات التي تم رميها بواسطة الطريقة باستخدام @throws في javadoc.
- الاستثناءات مكلفة، لذلك رمها فقط عندما يكون من المنطقي. في غير ذلك، يمكنك التقاطها وتقديم استجابة فارغة أو فارغة.
اقرأ المزيد عنها بالتفصيل في أفضل الممارسات في التعامل مع استثناءات جافا.
15. ما هي المشكلة في البرامج أدناه وكيف يمكننا إصلاحها؟
في هذا القسم، سننظر في بعض الأسئلة البرمجية المتعلقة باستثناءات جافا.
-
ما هي المشكلة في البرنامج أدناه؟
package com.journaldev.exceptions; import java.io.FileNotFoundException; import java.io.IOException; public class TestException { public static void main(String[] args) { try { testExceptions(); } catch (FileNotFoundException | IOException e) { e.printStackTrace(); } } public static void testExceptions() throws IOException, FileNotFoundException{ } }
لن يتم تجميع البرنامج أعلاه وستحصل على رسالة خطأ تقول “The exception FileNotFoundException is already caught by the alternative IOException”. هذا لأن FileNotFoundException هو فئة فرعية من IOException، وهناك طريقتان لحل هذه المشكلة. الطريقة الأولى هي استخدام كتلة catch واحدة لكلا الاستثناءين.
try { testExceptions(); }catch(FileNotFoundException e){ e.printStackTrace(); }catch (IOException e) { e.printStackTrace(); }
طريقة أخرى هي إزالة FileNotFoundException من الكتلة المتعددة catch.
try { testExceptions(); }catch (IOException e) { e.printStackTrace(); }
يمكنك اختيار أي من هذه الطرق استنادًا إلى كود الكتلة catch الخاص بك.
-
ما هو المشكلة مع البرنامج أدناه؟
package com.journaldev.exceptions; import java.io.FileNotFoundException; import java.io.IOException; import javax.xml.bind.JAXBException; public class TestException1 { public static void main(String[] args) { try { go(); } catch (IOException e) { e.printStackTrace(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (JAXBException e) { e.printStackTrace(); } } public static void go() throws IOException, JAXBException, FileNotFoundException{ } }
لن يتم تجميع البرنامج لأن FileNotFoundException هو فئة فرعية من IOException، لذا فإن كتلة اللتقاط لـ FileNotFoundException غير قابلة للوصول وستحصل على رسالة خطأ “كتلة اللتقاط لـ FileNotFoundException غير قابلة للوصول. تم التعامل بالفعل معها بواسطة كتلة اللتقاط لـ IOException”. عليك أن تقوم بترتيب كتل اللتقاط لحل هذه المشكلة.
try { go(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (JAXBException e) { e.printStackTrace(); }
لاحظ أن JAXBException غير مرتبطة بـ IOException أو FileNotFoundException ويمكن وضعها في أي مكان في التسلسل الهرمي لكتل اللتقاط أعلاه.
-
ما هو المشكلة مع البرنامج أدناه؟
package com.journaldev.exceptions; import java.io.IOException; import javax.xml.bind.JAXBException; public class TestException2 { public static void main(String[] args) { try { foo(); } catch (IOException e) { e.printStackTrace(); }catch(JAXBException e){ e.printStackTrace(); }catch(NullPointerException e){ e.printStackTrace(); }catch(Exception e){ e.printStackTrace(); } } public static void foo() throws IOException{ } }
البرنامج لن يترجم لأن JAXBException هو استثناء يتم التحقق من صحته ويجب على طريقة foo() رمي هذا الاستثناء ليتم التقاطه في الطريقة المستدعاة. ستحصل على رسالة خطأ “كتلة الاستثناء غير القابلة للوصول لـ JAXBException. لم يتم رمي هذا الاستثناء أبدًا من جسم تعليمة الـ try”. لحل هذه المشكلة، يجب إزالة كتلة الاستثناء لـ JAXBException. لاحظ أن التقاط NullPointerException صالح لأنه استثناء غير متحقق من صحته.
-
ما هي المشكلة مع البرنامج أدناه؟
package com.journaldev.exceptions; public class TestException3 { public static void main(String[] args) { try{ bar(); }catch(NullPointerException e){ e.printStackTrace(); }catch(Exception e){ e.printStackTrace(); } foo(); } public static void bar(){ } public static void foo() throws NullPointerException{ } }
هذا سؤال مضلل، لا يوجد مشكلة في الشيفرة وسوف يتم تجميعها بنجاح. يمكننا دائمًا الإمساك بـ استثناء Exception أو أي استثناء غير مفحوص حتى لو لم يكن ذلك موجودًا في الجملة throws للطريقة. بالمثل، إذا قامت طريقة (foo) بتعريف استثناء غير مفحوص في جملة throws، فليس من الضروري التعامل مع ذلك في البرنامج.
-
ما هي المشكلة في البرنامج أدناه؟
package com.journaldev.exceptions; import java.io.IOException; public class TestException4 { public void start() throws IOException{ } public void foo() throws NullPointerException{ } } class TestException5 extends TestException4{ public void start() throws Exception{ } public void foo() throws RuntimeException{ } }
لن يتم تجميع البرنامج أعلاه لأن توقيع الطريقة start() غير متطابق في الفصل الفرعي. لحل هذه المشكلة، يمكننا إما تغيير توقيع الطريقة في الفصل الفرعي ليكون مطابقًا تمامًا للفئة الأم، أو يمكننا إزالة عبارة الإلقاء من طريقة الفصل الفرعي كما هو موضح أدناه.
@Override public void start(){ }
-
ما هو المشكلة في البرنامج أدناه؟
package com.journaldev.exceptions; import java.io.IOException; import javax.xml.bind.JAXBException; public class TestException6 { public static void main(String[] args) { try { foo(); } catch (IOException | JAXBException e) { e = new Exception(""); e.printStackTrace(); }catch(Exception e){ e = new Exception(""); e.printStackTrace(); } } public static void foo() throws IOException, JAXBException{ } }
البرنامج أعلاه لن يتم تجميعه لأن كائن الاستثناء في الكتلة المتعددة الاصطياد هو ثابت ولا يمكننا تغيير قيمته. ستحصل على خطأ في وقت التجميع كـ “لا يمكن تعيين المعلمة e لكتلة الاصطياد المتعددة”. يجب أن نقوم بإزالة تعيين “e” إلى كائن استثناء جديد لحل هذا الخطأ. اقرأ المزيد في كتلة الاصطياد المتعددة في جافا 7.
هذا كل شيء بالنسبة لأسئلة استثناء جافا في المقابلات، آمل أن تعجبك. سأقوم بإضافة المزيد إلى القائمة في المستقبل، تأكد من حفظها للاستخدام المستقبلي.
Source:
https://www.digitalocean.com/community/tutorials/java-exception-interview-questions-and-answers