كتلة finally في Java: خرافات، واقع ومزالق
\n\nكل مطور Java، من المبتدئ إلى الخبير، يواجه عاجلاً أم آجلاً كتلة finally. في الكتب المدرسية يُكتب: "يتم تنفيذ هذه الكتلة دائمًا، بغض النظر عن حدوث استثناء أم لا". يبدو وكأنه ضمان حديدي، أليس كذلك؟ لكن دعونا نلقي نظرة خلف الكواليس.
على StackOverflow، سؤال "هل يتم تنفيذ كتلة finally دائمًا في Java؟" حصد آلاف المشاهدات ومئات التعليقات. المبرمجون ذوو الخبرة يتجادلون، والمبتدئون يضيعون، والحالات الواقعية تُظهر: "دائمًا" ليست حقيقة مطلقة. في هذه المقالة، سنحلل جميع السيناريوهات، ونكتب كودًا حقيقيًا، ونكتشف متى قد يخذلكم finally.
كيف يعمل finally؟ مثال أساسي
\n\nفي البداية - الكلاسيكي. تُستخدم كتلة finally لتحرير الموارد: إغلاق الملفات، اتصالات قواعد البيانات، المقابس (sockets). يتم تنفيذها بعد try (و catch، إذا كان هناك استثناء)، ولكن قبل أن يغادر التحكم الدالة.
public class FinallyDemo {\n public static void main(String[] args) {\n try {\n System.out.println("داخل try");\n int result = 10 / 2; // كل شيء جيد\n } catch (ArithmeticException e) {\n System.out.println("تم التقاط الاستثناء: " + e.getMessage());\n } finally {\n System.out.println("تم تنفيذ كتلة finally!");\n }\n System.out.println("البرنامج يستمر...");\n }\n}\n\nالإخراج:
\nداخل try\nتم تنفيذ كتلة finally!\nالبرنامج يستمر...\n\nكل شيء متوقع. لكن ماذا سيحدث إذا نشأ استثناء في try لم يتم التقاطه؟
public class FinallyWithUncaught {\n public static void main(String[] args) {\n try {\n System.out.println("محاولة القسمة على صفر...");\n int result = 10 / 0; // استثناء!\n } finally {\n System.out.println("يتم تنفيذ finally قبل أن يطير الاستثناء للأعلى");\n }\n // هذا السطر لن يتم تنفيذه\n System.out.println("هذا السطر لن يُطبع");\n }\n}\n\nالإخراج سيفاجئ المبتدئين:
\nمحاولة القسمة على صفر...\nيتم تنفيذ finally قبل أن يطير الاستثناء للأعلى\nException in thread "main" java.lang.ArithmeticException: / by zero\n at FinallyWithUncaught.main(FinallyWithUncaught.java:5)\n\nتم تنفيذ كتلة finally، على الرغم من أن الاستثناء لم يتم معالجته. هذا السلوك هو ما ولّد خرافة "دائمًا". لكن دعونا نتعمق أكثر.
متى لا يتم تنفيذ finally؟ سيناريوهات حقيقية
\n\nهناك على الأقل ثلاث حالات قد لا يتم فيها تنفيذ finally. احفظوها - ستوفر عليكم ساعات من التصحيح.
1. System.exit() - إنهاء JVM بشكل طارئ
\n\nالحالة الأكثر شهرة. إذا تم استدعاء System.exit(0) داخل كتلة try، تنتهي JVM فورًا، ولن يتم تنفيذ finally.
public class FinallyAndExit {\n public static void main(String[] args) {\n try {\n System.out.println("نبدأ العمل...");\n System.exit(0); // تنتهي JVM هنا\n } finally {\n // هذا الكود لن يتم تنفيذه!\n System.out.println("هل ظننتم أنني سأُنفذ؟ لا!");\n }\n }\n}\n\nالإخراج:
\nنبدأ العمل...\n\nلماذا؟ لأن System.exit() يوقف الآلة الافتراضية على مستوى نظام التشغيل. هذا ليس استثناءً - بل أمر "بالموت". كتلة finally ببساطة لا يتوفر لها الوقت للعمل.
System.exit() في الكود، توقف. هذا أسلوب سيء. لإنهاء البرنامج، استخدم