در این مقاله، نحوه عملکرد پدیده جاوا 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
همانطور که Стэк
از نامش پیداست کار می کند. در این مرحله کمی بیشتر به جزئیات خواهیم پرداخت. در سطح هشتم، قبلاً با مجموعه ها آشنا شده اید و می دانید که آنها به سه گروه 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
نیاز دارید ؟ بیایید به مثال خطای زیر که در حین اجرای چنین برنامه ساده ای رخ داده است نگاه کنیم. 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
که مقدار فعلی کار خود را زیر شماره 1convertStringToInt
قرار می دهد، سپس دوباره به متد و برنامه می رویم. پارامترهای مکان ما را وارد می کند که قبلاً StackTrace
در زیر شماره 2parseInt
ایجاد شده بود، سپس متدی نامرئی برای چشم ما که در کلاس قرار دارد نامیده می شود و این قبلا عنصر شماره 3 ما Integer
خواهد بود ، در این متد یک فراخوانی داخلی دیگر اضافه می شود. به عدد 4 برای بررسی null بودن عنصر که منجر به خطا می شود. برنامه باید خطای ما را نشان دهد که کل زنجیره انتقال ما را نشان می دهد تا زمانی که خطا رخ دهد. اینجاست که همانی که قبلاً با داده های انتقال ما ایجاد شده بود به کمک او می آید . StackTrace
StackTrace
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 در مثال) نامید که وقتی به آن اضافه شد، Стэк
شماره سه و متد این کلاس بود. هنوز برای ما قابل مشاهده نیست، با روش ما واقع در خط 10 برنامه ما (شماره 4 در مثال و هنگام اضافه کردن آن دوم بود) Integer
فراخوانی شد و به نوبه خود در خط 6 (شماره 5 در) فراخوانی شد. مثال، و هنگام اضافه کردن، به ترتیب، اول). بنابراین، با ذخیره گام به گام متدهای فراخوانی شده، توانستیم به چاپ موازی اطلاعاتی که دقیقاً ما را به خطا منجر شده است، برگردیم. اما این نه تنها با خطاها کار می کند، بلکه به ما امکان می دهد اطلاعات جالب زیادی در مورد روند برنامه خود به دست آوریم. بیایید به یک مثال محبوب دیگر در نظرات سخنرانی اصلی سطح 9 نگاه کنیم. ما کد را داریم و بلافاصله تصویری را به آن پیوست میکنم که روند برنامه را به تصویر میکشد: convertStringToInt
main
Стек
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());
}
}
}
در اینجا برنامه ما کار خود را بدون نقص انجام می دهد و به پایان می رسد. این چیزی است که در خروجی کنسول خواهیم دید:
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 می بینم ;)
GO TO FULL VERSION