JavaRush /وبلاگ جاوا /Random-FA /Stack Trace و آنچه که با آن خورده می شود
Alukard
مرحله
London

Stack Trace و آنچه که با آن خورده می شود

در گروه منتشر شد
در این مقاله، نحوه عملکرد پدیده جاوا StackTrace که با نام Call Stack Tracing نیز شناخته می شود را خواهید آموخت. این اطلاعات برای مبتدیانی که در ابتدای Java Syntax Level 9 با این مفهوم مواجه شدند، ساختار یافته است. فکر می‌کنم همه شما حداقل یک بار، بدون در نظر گرفتن اینکه Idea ، Eclipse یا چیز دیگری باشد، هنگام کار در IDE با خطاهای مشابهی مواجه شده‌اید.
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همانطور که Стэкاز نامش پیداست کار می کند. در این مرحله کمی بیشتر به جزئیات خواهیم پرداخت. مجموعه Stack چگونه کار می کند در سطح هشتم، قبلاً با مجموعه ها آشنا شده اید و می دانید که آنها به سه گروه Set- مجموعه، List- فهرست، Map- دیکشنری (یا نقشه) تقسیم می شوند. طبق JavaRush (c). مال ما Stackجزء گروهه Listاصل عملکرد آن را می توان به عنوان LIFO توصیف کرد که مخفف کلمه Last In First Out است. یعنی، این فهرستی شبیه به پشته‌ای از کتاب‌ها است؛ برای اینکه عنصری را که در Stackابتدا قرار داده‌ایم، برداریم، ابتدا باید تمام عناصری را که بعد از آن به لیست خود اضافه کرده‌ایم استخراج کنیم. همانطور که در تصویر بالا نشان داده شده است، بر خلاف، برای مثال، یک لیست معمولی ArrayListکه در آن می توانیم هر عنصری را از لیست به صورت شاخص دریافت کنیم. یک بار دیگر برای تقویت گرفتن یک عنصر از Стэкаفقط از انتها امکان پذیر است! در حالی که اولین عنصر اضافه شده به آن در ابتدا (یا در پایین، همانطور که راحت تر است) است. اینها روشهایی هستند که Stack Object ما دارد push()- یک عنصر را به بالای پشته اضافه می کند. Object pop()- عنصر را در بالای پشته برمی‌گرداند و در این فرآیند آن را حذف می‌کند. شی peek()- عنصر را در بالای پشته برمی گرداند، اما آن را حذف نمی کند. int search()- یک عنصر را در پشته جستجو می کند. در صورت یافتن، افست آن از بالای پشته برگردانده می شود. در غیر این صورت -1 برگردانده می شود. boolean empty()- بررسی می کند که آیا پشته خالی است. اگر پشته خالی باشد مقدار true را برمی گرداند. اگر پشته حاوی عناصر باشد، false را برمی‌گرداند. پس چرا به یکی که بر اساس اصول عملیات ساخته شده است Javaنیاز دارید ؟ بیایید به مثال خطای زیر که در حین اجرای چنین برنامه ساده ای رخ داده است نگاه کنیم. StackTraceStack
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که مقدار فعلی کار خود را زیر شماره 1convertStringToInt قرار می دهد، سپس دوباره به متد و برنامه می رویم. پارامترهای مکان ما را وارد می کند که قبلاً StackTraceدر زیر شماره 2parseInt ایجاد شده بود، سپس متدی نامرئی برای چشم ما که در کلاس قرار دارد نامیده می شود و این قبلا عنصر شماره 3 ما Integerخواهد بود ، در این متد یک فراخوانی داخلی دیگر اضافه می شود. به عدد 4 برای بررسی null بودن عنصر که منجر به خطا می شود. برنامه باید خطای ما را نشان دهد که کل زنجیره انتقال ما را نشان می دهد تا زمانی که خطا رخ دهد. اینجاست که همانی که قبلاً با داده های انتقال ما ایجاد شده بود به کمک او می آید . StackTraceStackTraceStackTrace
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 در مثال) نامید که وقتی به آن اضافه شد، Стэкشماره سه و متد این کلاس بود. هنوز برای ما قابل مشاهده نیست، با روش ما واقع در خط 10 برنامه ما (شماره 4 در مثال و هنگام اضافه کردن آن دوم بود) Integerفراخوانی شد و به نوبه خود در خط 6 (شماره 5 در) فراخوانی شد. مثال، و هنگام اضافه کردن، به ترتیب، اول). بنابراین، با ذخیره گام به گام متدهای فراخوانی شده، توانستیم به چاپ موازی اطلاعاتی که دقیقاً ما را به خطا منجر شده است، برگردیم. اما این نه تنها با خطاها کار می کند، بلکه به ما امکان می دهد اطلاعات جالب زیادی در مورد روند برنامه خود به دست آوریم. بیایید به یک مثال محبوب دیگر در نظرات سخنرانی اصلی سطح 9 نگاه کنیم. ما کد را داریم و بلافاصله تصویری را به آن پیوست می‌کنم که روند برنامه را به تصویر می‌کشد: convertStringToIntmainСтекmainStackTrace
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 چه اتفاقی افتاد؟ می ترسم بهترین کاری که می توانم انجام دهم این است که محبوب ترین توضیح (به اختصار) توسط کاربر Kirill را از نظرات به سخنرانی اضافه کنم. بیایید به خط ایجاد برگردیم StackTraceو آن را عنصر به عنصر تجزیه و تحلیل کنیم:
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
StackTraceElement[]- نشانه ای از نوع آرایه (در سطوح اولیه شما قبلاً در مورد آرایه هایی مانند int[]، String[] یاد گرفته اید، اینجا هم همینطور است). stackTraceElements- نام آرایه می تواند هر چیزی باشد، با در نظر گرفتن قوانین کلی نامگذاری، این روی کار تأثیر نمی گذارد. Thread.currentThread()- به دست آوردن پیوندی به رشته فعلی که در آن متدهایی که می خواهیم ردیابی کنیم اجرا می شود (در حال حاضر این مهم نیست، شما موضوعات را با جزئیات بیشتری در سطح 16 در جستجوی Java Core تجزیه و تحلیل خواهید کرد) - ما همه متدهای فراخوانی شده را getStackTrace()دریافت می کنیم Стэк(این یک دریافت کننده معمولی برای StackTrace) است حالا بیایید ببینیم آرایه ایجاد شده چه چیزی برای ما مفید است. ما می دانیم که آرایه اطلاعات مربوط به روش های اجرا شده را ذخیره می کند. (ج) و برای این، در خط 21، ما یک چرخه تغییر یافته forبه نام forEach(به هر حال، برای کسانی که هنوز این چرخه را مطالعه نکرده اند، توصیه می کنم در مورد آن مطالعه کنند) راه اندازی می کنیم و داده ها را از آرایه به کنسول خروجی می کنیم. ، یعنی اطلاعاتی در مورد اینکه کدام روش در طول کار با استفاده از ساخت و ساز اجرا شده است element.getMethodName(). توجه، همانطور که می بینیم، عنصر صفر آرایه به ترتیب خودش بود getStackTrace()، زیرا در لحظه دریافت آرایه داده، آخرین روشی بود که اجرا شد و در نتیجه در بالای صفحه قرار گرفت Стэкаو ساخت ما را به خاطر آورد. Last in, first out بلافاصله اولین موردی است که به آرایه زیر عنصر صفر اضافه می شود. در اینجا چه چیز دیگری می توانیم از آن دریافت کنیم StackTraceElement: String getClassName()- نام کلاس را برمی گرداند. String getMethodName()- نام متد را برمی‌گرداند. String getFileName()- نام فایل را برمی‌گرداند (کلاس‌های زیادی در یک فایل وجود دارد). رشته getModuleName()- نام ماژول را برمی گرداند (می تواند تهی باشد). رشته getModuleVersion()- نسخه ماژول را برمی گرداند (می تواند تهی باشد). int getLineNumber()- شماره خط را در فایلی که متد در آن فراخوانی شده است، برمی گرداند. اکنون که اصل کلی عملکرد را درک کرده اید، به شما توصیه می کنم روش های مختلفی را خودتان StackTraceدر ایده خود امتحان کنید . حتی اگر به همه چیز تسلط کامل نداشته باشید، به یادگیری ادامه دهید و معما به همان شکلی که برای من در این مورد پیدا شد تبدیل خواهد شد. برای همه شما آرزوی موفقیت دارم! Ps اگر این مطالب را دوست داشتید با لایک حمایت کنید. برای شما سخت نیست، من راضی هستم. با تشکر و شما را در سطح 41 می بینم ;)
نظرات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION