JavaRush /مدونة جافا /Random-AR /Stack Trace وما يؤكل به
Alukard
مستوى
London

Stack Trace وما يؤكل به

نشرت في المجموعة
في هذه المقالة، سوف تتعلم وتفهم كيفية عمل ظاهرة Java StackTrace، والمعروفة أيضًا باسم Call Stack Tracing. تم تنظيم هذه المعلومات للمبتدئين الذين واجهوا هذا المفهوم في بداية Java Syntax Level 9. أعتقد أنكم جميعًا، مرة واحدة على الأقل، واجهتم أخطاء مماثلة عند العمل في IDE الخاص بكم، بغض النظر عما إذا كان Idea أو Eclipse أو أي شيء آخر.
Exception in thread "main" java.lang.ArithmeticException
	at com.example.task01.Test.division(Test.java:10)
	at com.example.task01.Test.main(Test.java:6)
هذا، كما كنت قد خمنت، هو تتبعنا. لكن لا تتسرع في الذعر، الآن سنشرح لك هذا المثال. عليك أولاً أن تفهم حقيقة أنه StackTraceيعمل كما Стэкيوحي اسمه. في هذه المرحلة سوف نتناول المزيد من التفاصيل. كيف تعمل مجموعة المكدس في المستوى الثامن، تكون قد تعرفت بالفعل على المجموعات وتعرف أنها مقسمة إلى ثلاث مجموعات Set- المجموعة، List- القائمة، Map- القاموس (أو الخريطة). وفقًا لـ JavaRush (ج). بلدنا Stackهو جزء من المجموعة List. يمكن وصف مبدأ تشغيله بـ LIFO ، والذي يرمز إلى Last In First Out. وهي قائمة تشبه مجموعة من الكتب؛ لكي نأخذ العنصر الذي وضعناه Stackأولاً، نحتاج أولاً إلى استخراج جميع العناصر التي أضفناها إلى قائمتنا بعد ذلك. كما هو موضح في الصورة أعلاه، على عكس القائمة العادية، على سبيل المثال، ArrayListحيث يمكننا الحصول على أي عنصر من القائمة عن طريق الفهرس. مرة أخرى للتعزيز. الحصول على عنصر من Стэкаالممكن فقط من النهاية! بينما أول عنصر يضاف إليه يكون في البداية (أو في الأسفل كما هو أكثر ملاءمة). هذه هي الأساليب التي يستخدمها Stack كائننا push()- لإضافة عنصر إلى أعلى المكدس. الكائن pop()- يقوم بإرجاع العنصر الموجود أعلى المكدس، وإزالته في العملية. الكائن peek()- يقوم بإرجاع العنصر الموجود أعلى المكدس، لكنه لا يقوم بإزالته. int search()- يبحث عن عنصر في المكدس. إذا تم العثور عليه، فسيتم إرجاع إزاحته من أعلى المكدس. وإلا يتم إرجاع -1. منطقي empty()- يتحقق مما إذا كان المكدس فارغًا. يُرجع صحيحًا إذا كان المكدس فارغًا. إرجاع خطأ إذا كانت المكدس يحتوي على عناصر. فلماذا تحتاج Javaإلى StackTraceواحدة مبنية على مبادئ التشغيل Stack؟ دعونا نلقي نظرة على مثال الخطأ أدناه الذي حدث أثناء تنفيذ مثل هذا البرنامج البسيط.
public class Test {

    public static void main(String[] args) {
        System.out.println(convertStringToInt(null));
    }

    public static int convertStringToInt(String s) {
        int x = Integer.parseInt(s);
        return x;
    }
}
لدينا فئة Testمع طريقتين. الجميع على دراية mainبالمنطق convertStringToIntالذي يتمثل في تحويل وإرجاع سلسلة مستلمة من الخارج (أي من الطريقة main) إلى عدد صحيح من النوع int. كما ترون، قمنا بتمرير المعلمة عمدًا بدلاً من سلسلة تحتوي على بعض الأرقام null. لم تتمكن طريقتنا من معالجة هذه المعلمة بشكل صحيح وتسببت في حدوث خطأ NumberFormatException. كما تعلمون يبدأ البرنامج في عمل عمله من الطريقة mainوفي هذه اللحظة يقوم بإنشاء واحدة جديدة Стэкباسم StackTraceحيث يضع القيمة الحالية لعمله تحت رقم 1 ثم ننتقل إلى الطريقة convertStringToIntوالبرنامج مرة أخرى يدخل معلمات موقعنا إلى تلك التي تم إنشاؤها مسبقًا StackTraceتحت الرقم 2 ، ثم يطلق عليها طريقة غير مرئية لأعيننا parseIntالموجودة في الفصل Integerوسيكون هذا بالفعل العنصر رقم 3 الخاص بنا StackTrace، وفي هذه الطريقة ستتم إضافة مكالمة داخلية أخرى إلى StackTraceالرقم 4 للتحقق من وجود العنصر خاليًا مما سيؤدي إلى حدوث خطأ. يحتاج البرنامج إلى عرض الخطأ الخاص بنا مع الإشارة إلى سلسلة التحولات بأكملها حتى حدوث الخطأ. هذا هو المكان الذي يأتي لمساعدتها الذي تم إنشاؤه مسبقًا ببيانات التحولات لدينا StackTrace.
Exception in thread "main" java.lang.NumberFormatException: null
	at java.base/java.lang.Integer.parseInt(Integer.java:614)
	at java.base/java.lang.Integer.parseInt(Integer.java:770)
	at com.example.task01.Test.convertStringToInt(Solution.java:10)
	at com.example.task01.Test.main(Solution.java:6)
قبل حدوث الخطأ، تعمق البرنامج في الأساليب، ولكن بمجرد حدوث الخطأ، بدأ كل شيء يحدث بالترتيب العكسي. تتم طباعة سطر يصف المشكلة (رقم 1 في المثال)، ثم يتم أخذ القيمة الأخيرة (وفي الأعلى) المضافة إلى قيمتنا، Стэкوكانت رقم أربعة وطباعتها على وحدة التحكم (رقم 2 في المثال) و نرى أن المشكلة نشأت في الفصل Integerعند سطر 614 من التعليمات البرمجية ويسمى هذا السطر، السطر 770 من طريقة parseIntمن نفس الفئة (رقم 3 في المثال) والتي، عند إضافتها، Стэкكانت رقم ثلاثة وطريقة الفئة هذه، Integerلا يزال غير مرئي لنا، تم استدعاؤه بواسطة طريقتنا convertStringToIntالموجودة في السطر 10 من برنامجنا (رقم 4 في المثال، وعند إضافته كان ثانيًا)، وتم استدعاؤه بدوره mainعلى السطر 6 (رقم 5 في المثال، وعند إضافة الأول على التوالي). لذلك، من خلال تخزين Стекأساليبنا المطلوبة خطوة بخطوة، تمكنا من العودة إلى mainالطباعة المتوازية للمعلومات التي قادتنا بالضبط إلى الخطأ. لكن StackTraceهذا لا يقتصر على التعامل مع الأخطاء فحسب، بل يتيح لنا الحصول على الكثير من المعلومات المثيرة للاهتمام حول عملية تقديم طلبنا. دعونا نلقي نظرة على مثال شائع آخر في التعليقات على المحاضرة الرئيسية للمستوى التاسع. لدينا الكود وسأرفق له على الفور صورة توضح عملية البرنامج:
public class Test {
    public static void main(String[] args) {
        method1();
        method2();
    }
    public static void method1() {
        //не вызывает ничего
    }
    public static void method2() {
        method3();
        method4();
    }
    public static void method3() {
        //не вызывает ничего
    }
    public static void method4() {
        method5();
    }
    public static void method5() {
        StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
        for (StackTraceElement element:stackTraceElements) {
            System.out.println(element.getMethodName());
        }
    }
}
Stack Trace وما يؤكل به - 2 هنا يقوم برنامجنا بعمله بشكل لا تشوبه شائبة وينتهي. وهذا ما سنراه في إخراج وحدة التحكم:
getStackTrace
method5
method4
method2
main

Process finished with exit code 0
كيف وصلنا إلى هذه النتيجة وماذا حدث في الطريقة الخامسة ابتداء من السطر 20؟ أخشى أن أفضل ما يمكنني فعله هو إضافة الشرح الأكثر شيوعًا (المختصر) بواسطة المستخدم كيريل من التعليقات على المحاضرة. دعنا ننتقل إلى خط الإنشاء StackTraceونحلله عنصرًا بعنصر:
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
StackTraceElement[]- إشارة إلى نوع المصفوفة (في المستويات المبكرة، تعلمت بالفعل عن المصفوفات مثل int[]، String[]، وهنا نفس الشيء). stackTraceElements- يمكن أن يكون اسم المصفوفة أي شيء، مع مراعاة قواعد التسمية العامة، وهذا لا يؤثر على العمل. Thread.currentThread()- الحصول على رابط للسلسلة الحالية التي يتم فيها تنفيذ الطرق التي نريد تتبعها (في الوقت الحالي، هذا ليس مهمًا، سوف تقوم بتحليل سلاسل الرسائل بمزيد من التفصيل في المستوى 16 في مهمة Java Core) getStackTrace()- نحصل على جميع Стэкالطرق المسماة (هذا هو getter العادي لـ StackTrace) الآن دعونا نرى ما قد تكون المصفوفة التي تم إنشاؤها مفيدة لنا. نحن ندرك أن المصفوفة تخزن معلومات حول الطرق المنفذة. (ج) ولهذا، في السطر الحادي والعشرين، نطلق دورة معدلة forتسمى forEach(بالمناسبة، لأولئك الذين لم يدرسوا هذه الدورة بعد، أنصحك بالقراءة عنها) ونخرج البيانات من المصفوفة إلى وحدة التحكم وهي معلومات حول الأساليب التي تم تنفيذها أثناء العمل باستخدام البناء element.getMethodName(). انتبه، كما نرى، تبين أن العنصر الصفري للمصفوفة هو نفسه، getStackTrace()على التوالي، لأنه في لحظة استلام مصفوفة البيانات كانت هي الطريقة الأخيرة التي تم تنفيذها وبالتالي انتهى بها الأمر في الأعلى Стэка، وتذكر البناء الخاص بنا " "آخر ما يدخل، يخرج أولاً " هو على الفور أول ما تتم إضافته إلى المصفوفة تحت العنصر الصفري. إليك ما يمكننا الحصول عليه أيضًا StackTraceElement: سلسلة getClassName()- تُرجع اسم الفئة. سلسلة getMethodName()- تقوم بإرجاع اسم الطريقة. سلسلة getFileName()- تقوم بإرجاع اسم الملف (يمكن أن يكون هناك العديد من الفئات في ملف واحد). سلسلة getModuleName()- تُرجع اسم الوحدة (يمكن أن يكون فارغًا). سلسلة getModuleVersion()- تُرجع إصدار الوحدة (يمكن أن يكون فارغًا). int getLineNumber()- يُرجع رقم السطر في الملف الذي تم استدعاء الطريقة فيه. الآن بعد أن فهمت المبدأ العام للتشغيل، أنصحك بتجربة طرق مختلفة بنفسك StackTraceفي Ide . حتى لو لم تتقن كل شيء تمامًا، واصل التعلم وسيظهر اللغز بنفس الطريقة التي ظهر بها بالنسبة لي في هذا الشأن. وأتمنى لكم كل النجاح والتوفيق! ملاحظة: إذا أعجبتك هذه المادة، فيرجى دعمها بإعجاب. ليس من الصعب عليك، أنا مسرور. شكرا ونراكم في المستوى 41 ;)
تعليقات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION