Menu
flag Ar iconالعربيةdown icon

Java try-catch: معالجة الاستثناءات دون تعطّل البرنامج

كيفية استخدام try-catch في جافا لمعالجة الاستثناءات - التقاط أنواع محددة، وكتلة finally، وtry-with-resources، والأخطاء التي تُخفي العلل.

تحتوي هذه الصفحة على محررات قابلة للتشغيل - حرّر، شغّل، وشاهد النتيجة فوراً.

التقاط استثناء بدلًا من التعطّل

أنت تعرف بالفعل أنه حين يحدث خطأ ما، فإن جافا تُطلق استثناءً، وأن الاستثناء غير المُعالَج يوقف برنامجك مع تتبُّع للمكدّس (stack trace). كتلة try-catch هي طريقتك لتولّي زمام الأمور: تُحيط الكود الخطِر بـ try، وإن أطلق استثناءً تنتقل جافا إلى كتلة catch المطابقة بدلًا من التعطّل.

في اللحظة التي يُطلق فيها 10 / 0 الاستثناء، يُتجاوَز باقي كتلة try وينتقل التحكّم إلى catch. وبعد انتهاء catch، يستمر التنفيذ بشكل طبيعي - فالبرنامج لا يموت.

متغيّر catch يحمل الاستثناء

الـ e في catch (ArithmeticException e) هو كائن حقيقي. إنه يحمل معلومات عمّا حدث من خطأ، وأكثرها فائدةً رسالة:

تُعيد e.getMessage() وصفًا موجزًا. أثناء التنقيح، يطبع e.printStackTrace() التتبُّع الكامل الذي يُظهر بالضبط من أين جاء الاستثناء - لُذ به حين لا تكفي الرسالة وحدها للعثور على السبب.

التقط النوع المحدد، لا كل شيء

تلتقط كتلة catch الاستثناءات المطابقة لنوعها المُصرَّح به (أو لأحد أنواعه الفرعية) فقط. أكبر خطأ يقع فيه المبتدئون هو التقاط Exception لجعل مشكلة ما "تختفي":

// لا تفعل هذا - فهو يُخفي عللًا حقيقية
try {
    doWork();
} catch (Exception e) {
    // يبتلع NullPointerException والأخطاء المطبعية وأخطاء المنطق... كل شيء
}

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

معالجة عدة أنواع من الاستثناءات

يمكنك رصّ عدة كتل catch. تفحصها جافا من الأعلى إلى الأسفل وتُنفّذ أول كتلة مطابقة، لذا رتّبها من الأكثر تحديدًا إلى الأكثر عمومية:

حين يتشارك نوعان المعالجة نفسها، استخدم كتلة multi-catch واحدة مع | بدلًا من تكرار الكتلة:

مَزلق ينبغي الانتباه له: النوع الأكثر عمومية يجب أن يأتي بعد الأنواع المحددة. وضع catch (Exception e) أولًا يجعل الكتل الأكثر تحديدًا التالية غير قابلة للوصول، ويرفض المُصرِّف ذلك.

finally تُنفَّذ دائمًا

تُنفَّذ كتلة finally بعد الـ try وأي catch، بصرف النظر عمّا حدث - نجاح، أو استثناء مُلتقَط، أو حتى return مبكر. وهي المكان الذي تنتمي إليه أعمال التنظيف التي يجب أن تحدث دائمًا.

تُطبَع "Closing resource" سواء أطلق الاستثناء أم لم يُطلق. لكن تجنّب تنفيذ return من داخل finally - فقد يتجاهل بصمت استثناءً أو يطغى على قيمة أُعيدت من كتلة try.

try-with-resources يغلق الأشياء نيابةً عنك

حين تتعامل مع شيء يجب إغلاقه - ملف، أو اتصال شبكي، أو تعليمة قاعدة بيانات - فإن التصريح به داخل try (...) يغلقه تلقائيًا عند انتهاء الكتلة، حتى لو أُطلق استثناء. ويعمل ذلك مع أي نوع يُطبّق AutoCloseable.

يحل هذا محل النمط القديم القائم على الفتح في try والإغلاق في finally، وهو أقل عرضةً للأخطاء لأنك لا تستطيع نسيان الإغلاق. فضّله كلما كنت تتعامل مع مورد قابل للإغلاق.

لا تستخدم الاستثناءات في تدفّق التحكّم العادي

try-catch مخصص للحالات الاستثنائية، لا للظروف الاعتيادية. التقاط استثناء أكثر كلفةً من فحص بسيط، ويجعل الكود أصعب قراءةً. إن كان بإمكانك فحص الشرط أولًا، فافعل ذلك بدلًا منه:

// تجنّب: استخدام catch لفحص مفتاح مفقود
try {
    process(map.get(key).trim());
} catch (NullPointerException e) {
    // معالجة المفتاح المفقود
}

// فضّل: الفحص الصريح
String value = map.get(key);
if (value != null) {
    process(value.trim());
}

احتفظ بـ catch للأمور الخارجة فعلًا عن سيطرتك - إدخال مستخدم خاطئ، أو ملفات مفقودة، أو أعطال شبكية.

التالي: NullPointerException

الاستثناء الأكثر شيوعًا الذي ستلتقطه (وتُسبّبه) في جافا هو NullPointerException - يظهر في اللحظة التي تستدعي فيها دالةً على شيء تبيّن أنه null. سنتعمّق تاليًا فيما يُطلقه بالضبط، وكيف تقرأ تتبُّع مكدّسه، والعادات التي تمنع حدوثه من الأساس.

الأسئلة الشائعة

كيف تستخدم try-catch في جافا؟

ضع الكود الذي قد يُطلق استثناءً داخل كتلة try، ثم أضف كتلة catch تُسمّي نوع الاستثناء الذي تريد معالجته: try { risky(); } catch (IOException e) { ... }. إذا أطلق كود الـ try استثناءً مطابقًا، تنتقل جافا مباشرةً إلى كتلة catch بدلًا من التعطّل. يحمل المتغير (e) كائن الاستثناء، فتستطيع قراءة رسالته عبر e.getMessage().

ما الغرض من كتلة finally في جافا؟

تُنفَّذ كتلة finally بعد try/catch مهما حدث - سواء نجح الكود أو أطلق استثناءً أو حتى نفّذ return مبكرًا. إنها المكان المناسب لأعمال التنظيف التي يجب أن تحدث دائمًا، مثل إغلاق ملف أو تحرير قفل. أما لإغلاق الموارد، فعادةً ما يكون try-with-resources أنظف لأنه يغلقها تلقائيًا.

هل ينبغي التقاط Exception أم نوع استثناء محدد؟

التقط أكثر نوع تحديدًا تستطيع معالجته فعليًا. التقاط Exception (أو الأسوأ، Throwable) يبتلع كل مشكلة - بما في ذلك علل مثل NullPointerException - ويُخفي السبب الحقيقي. التقط NumberFormatException إن كان هذا ما تتوقعه، ودع الاستثناءات غير المتوقعة تنتشر كي تعرف بأمرها.

Coddy programming languages illustration

تعلّم البرمجة مع Coddy

ابدأ الآن