أخطاء التشغيل

برنامجي يعلق
إذا توقف البرنامج وبدا انه لا يفعل أي شيء، نقول أنه يعلق (أو يجمد hang). ذلك يكون معناه غالباً أن البرنامج دخل في حلقة لا نهائية أو عملية عودية لا نهائية.
· في حال وجود حلقة معينة تشك أنها سبب المشكلة، أضف تعليمة طباعة قبل الحلقة مباشرة تقول "entering the loop". وواحدة أخرى بعد الحلقة مباشرة تقول
"exiting the loop".
شغل البرنامج. إذا حصلت على الجملة الأولى دون الثانية، فمشكلتك هي حلقة لا نهائية. اذهب إلى قسم "الحلقات اللانهائية".
· في معظم الأوقات سيسبب التعاود اللانهائي تشغيل البرنامج لفترة من الزمن ثم يولد StackOverflowException. إذا حدث ذلك، اذهب إلى قسم "التعاود اللانهائي".
إذا لم تكن تحصل على StackOverflowException، لكنك تشك بوجود مشكلة في عملية عودية، فلا يزال استعمال الأساليب الموجودة في قسم التعاود اللانهائي ممكناً.
· إذا لم تنفع أياً من هذه المقترحات، فقد لا تكون مستوعباً لمجرى التنفيذ في برنامجك. اذهب إلى قسم "مجرى التنفيذ".

الحلقات اللانهائية

إذا كنت تعتقد أنك تملك حلقة لا نهائية وكنت تعرف أية حلقة هي، أضف تعليمة طباعة في نهاية الحلقة تطبع قيم المتغيرات الموجودة في الجملة الشرطية، وقيمة الشرط.
مثلاً،
كود:
while (x > 0 && y < 0) {                              
   // do something to x
   // do something to y
 
   System.out.println("x: " + x);
   System.out.println("y: " + y);
   System.out.println("condition: " + (x > 0 && y < 0));
}
الآن عندما تشغل البرنامج سترى ثلاثة أسطر من الخرج في كل مرة تدور فيها الحلقة. في آخر مرة يتم تنفيذ الحلقة فيها، يجب أن تكون قيمة الشرط false. إذا استمرت الحلقة بالعمل، انظر إلى قيم x وy فقد تعرف سبب عدم تحديثهما بشكل صحيح.

التعاود اللانهائي

في أغلب الأحيان يسبب التعاود اللانهائي توليد استثناء StackOverflowException. لكن إذا كان البرنامج بطيئاً فقد يستغرق وقتاً طويلاً قبل أن يملأ المكدس.
إذا كنت تعرف أية عملية هي سبب المشكلة، تحقق من وجود حالة قاعدية فيها. يجب وجود شرط يجعل العملية تنتهي بدون عمل استدعاء تعاودي آخر. إذا لم توجد حالة قاعدية للعملية، عليك إعادة التفكير بالخوارزمية وتعريف حالة قاعدية لها.
في حال وجود حالة قاعدية، لكن لا يبدو أن البرنامج يصل إليها، أضف تعليمة طباعة إلى بداية العملية تطبع معاملاتها. يجب أن ترى الآن بضعة أسطر من الخرج عند كل استدعاء للعملية، ترى فيه قيم معاملاتها. إذا لم تتحرك المعاملات نحو الحالة القاعدية، فقد تتمكن من رؤية السبب.

مجرى التنفيذ
إذا لم تكن متأكداً من حركة مجرى التنفيذ في البرنامج، أضف تعليمات طباعة إلى بداية كل عملية تطبع رسالة مثل "entering method foo"، حيث foo اسم العملية.
عندما تشغل البرنامج الآن فسوف يترك أثراً لكل عملية يتم استدعائها.
يمكن طباعة المتحولات التي تستقبلها كل عملية أيضاً. عندما تشغل البرنامج، تأكد أن القيم منطقية، وتحقق من عدم وقوعك في أكثر الأخطاء شيوعاً – توفير المتحولات بترتيب خاطئ.

عندما أشغل البرنامج يولد استثناء
عند حدوث استثناء، تطبع Java رسالة تتضمن اسم الاستثناء، السطر الذي حدثت فيه المشكلة، وسجل المكدس.
يحتوي سجل المكدس (stack trace) على العملية التي كانت تعمل أثناء حدوث الخطأ، العملية التي استدعتها، والعملية التي استدعت العملية التي سبقتها، وهكذا.
الخطوة الأولى هي فحص المكان الذي حدث فيه الخطأ ومحاولة اكتشاف ما الذي جرى.
NullPointerException: لقد حاولت الولوج إلى متغير حالة أو استدعاء عملية على كائن معدوم (null object). عليك معرفة أي متغير هو المعدوم ثم معرفة
السبب وراء وصوله إلى تلك الحالة.
تذكر أن التصريح عن متغيرات من نوع كائني (object type)، يكون معدوماً في الحالة الابتدائية، ويظل هكذا حتى تسند له قيمة. مثلاً، هذه الشفرة تسبب NullPointerException:

ArrayIndexOutOfBoundsException: الدليل الذي تستخدمه للوصول إلى عناصر مصفوفة إما أن يكون سالباً أو أكبر من array.length-1. إذا عثرت على الموقع الذي حدثت تلك المشكلة فيه، أضف تعليمة طباعة قبله تماماً تطبع قيمة الدليل (index) وطول المصفوفة. هل حجم المصفوفة صحيح؟ هل قيمة الدليل صحيحة؟
الآن أعمِل طريقك رجوعاً في البرنامج وابحث عن المكان الذي جاءت منه المصفوفة وجاء منه الدليل. اعثر على أقرب تعليمة إسناد وتحقق من أنها تعمل بشكل الصحيح.
إذا كان أحدهما معاملاً، اذهب إلى مكان استدعاء العملية وانظر إلى المكان الذي أتت منه القيم.
StackOverflowException: انظر "التعاود اللانهائي".
FileNotFoundException: هذا يعني أن Java لم تعثر على الملف الذي كانت تبحث عنه. إذا كنت تستخدم بيئة برمجة تعتمد المشاريع كأساس للعمل، مثل Eclipse، فقد تحتاج إلى استيراد الملف إلى المشروع. وإلا عليك التأكد أن الملف موجود فعلاً وأن مساره صحيح. هذه المشكلة تعتمد على نظام الملفات لديك.
ArithmeticException: يحدث عند حدوث خطأ أثناء عملية رياضية، أغلب الأحيان بسبب القسمة على صفر.

لقد أضفت تعليمات طباعة كثيرة لدرجة أنني غرقت بمخرجات البرنامج

إحدى المشاكل التي تحدث عند استعمال تعليمات الطباعة لتنقيح البرامج هي احتمال أن تنتهي مدفوناً بالمخرجات. يوجد طريقتين للمتابعة: إما أن تبسط الخرج، أو أن تبسط البرنامج.
حتى تبسط المخرجات يمكنك حذف تعليمات الطباعة الغير مفيدة أو تحويلها إلى تعليقات، أو جمعها معاً، أو تنسيق المخرجات حتى تصبح أسهل للفهم. أثناء تطوير أي برنامج، عليك كتابة شفرة لتوليد معلومات بصرية مختصرة عما يفعله البرنامج.
لتبسيط البرنامج، صغر حجم المشكلة التي يعالجها البرنامج. مثلاً، إذا كنت تعمل على ترتيب مصفوفة، رتب مصفوفة صغيرة. إذا كان البرنامج يستقبل مدخلات من المستخدم، أعطه أبسط مقدار من المعطيات التي تسبب الخطأ.
أيضاً، قم بتنظيف الشفرة. أزل الشفرة الميتة وأعد ترتيب البرنامج حتى يصبح أسهل للقراءة. مثلاً، إذا شككت بأن الخطأ يحدث في مكان عميق التداخل من البرنامج، أعد كتابة ذاك الجزء باستخدام بنية أبسط. إذا شككت بأمر عملية ضخمة، قسّمها إلى عمليات أصغر واختبر كل واحدة لوحدها.
عملية البحث عن أبسط حالة اختبار غالباً ما تقودك إلى الخطأ. مثلاً، إذا وجدت أن البرنامج يعمل عندما يكون عدد عناصر المصفوفة زوجياً، ولا يعمل عندما يكون عدد عناصرها فردياً، فذلك دليل يفيدك في معرفة ما يجري.
يمكن أن تساعدك إعادة ترتيب البرنامج للعثور على الأخطاء الخبيثة. مثلاً، لو غيرت شيئاً في البرنامج وكنت تعتقد أن هذا التغيير لن يؤثر