1. รับการติดตามสแต็ก

รับการติดตามสแต็ก

ภาษาโปรแกรม Java มีหลายวิธีสำหรับโปรแกรมเมอร์ในการรับข้อมูลเกี่ยวกับสิ่งที่เกิดขึ้นในโปรแกรม และไม่ใช่แค่คำพูดเท่านั้น

ตัวอย่างเช่น หลังจากโปรแกรม C++ ถูกคอมไพล์แล้ว โปรแกรมเหล่านั้นจะกลายเป็นไฟล์ขนาดใหญ่หนึ่งไฟล์ที่เต็มไปด้วยรหัสเครื่อง และทั้งหมดที่มีให้สำหรับโปรแกรมเมอร์ในขณะรันไทม์คือแอดเดรสของบล็อกหน่วยความจำที่มีรหัสเครื่องที่กำลังดำเนินการอยู่ ไม่เยอะนะขอบอก

แต่สำหรับ Java แม้ว่าโปรแกรมจะถูกคอมไพล์แล้ว คลาสก็ยังคงเป็นคลาส เมธอดและตัวแปรไม่หายไป และโปรแกรมเมอร์มีหลายวิธีในการรับข้อมูลเกี่ยวกับสิ่งที่เกิดขึ้นในโปรแกรม

การติดตามสแต็ก

ตัวอย่างเช่น ในการดำเนินการของโปรแกรม คุณสามารถค้นหาคลาสและชื่อของเมธอดที่กำลังดำเนินการอยู่ และไม่ใช่เพียงเมธอดเดียวเท่านั้น คุณสามารถรับข้อมูลเกี่ยวกับสายการเรียกใช้เมธอดทั้งหมดจากเมธอดปัจจุบันกลับไปยังmain()เมธอด

รายการที่ประกอบด้วยเมธอดปัจจุบัน และเมธอดที่เรียกใช้ และเมธอดที่เรียกใช้เมธอดนั้น ฯลฯ เรียกว่าสแต็กเทรซ คุณสามารถรับได้ด้วยคำสั่งนี้:

StackTraceElement[] methods = Thread.currentThread().getStackTrace();

คุณยังสามารถเขียนเป็นสองบรรทัด:

Thread current = Thread.currentThread();
StackTraceElement[] methods = current.getStackTrace();

เมธอดแบบ สแตติกcurrentThread()ของThreadคลาสจะส่งคืนการอ้างอิงไปยังThreadออบเจกต์ ซึ่งมีข้อมูลเกี่ยวกับเธรดปัจจุบัน เช่น เธรดปัจจุบันของการดำเนินการ คุณจะได้เรียนรู้เพิ่มเติมเกี่ยวกับเธรดในระดับ 17 และ 18 ของภารกิจJava Core

อ็อบเจกต์ นี้ThreadมีgetStackTrace()เมธอดซึ่งส่งคืนอาร์เรย์ของStackTraceElementออบเจกต์ ซึ่งแต่ละอาร์เรย์มีข้อมูลเกี่ยวกับเมธอด เมื่อนำมารวมกัน องค์ประกอบเหล่านี้ทั้งหมดจะก่อตัวเป็นสแต็กเทร

ตัวอย่าง:

รหัส
public class Main
{
   public static void main(String[] args)
   {
      test();
   }

   public static void test()
   {
      Thread current = Thread.currentThread();
      StackTraceElement[] methods = current.getStackTrace();

      for(var info: methods)
         System.out.println(info);
   }
}
เอาต์พุตคอนโซล
java.base/java.lang.Thread.getStackTrace(Thread.java:1606)
Main.test(Main.java:11)
Main.main(Main.java:5)

ดังที่เราเห็นในเอาต์พุตคอนโซลของตัวอย่าง เมธอดgetStackTrace()ส่งคืนอาร์เรย์ขององค์ประกอบสามรายการ:

  • getStackTrace()วิธีการของThreadชั้นเรียน
  • test()วิธีการของMainชั้นเรียน
  • main()วิธีการของMainชั้นเรียน

จากสแต็กเทรซนี้ เราสามารถสรุปได้ว่า:

  • เมธอด นี้Thread.getStackTrace()ถูกเรียกโดยMain.test()เมธอดในบรรทัดที่ 11 ของไฟล์ Main.java
  • เมธอดMain.test()ถูกเรียกโดยMain.main()เมธอดในบรรทัดที่ 5 ของไฟล์ Main.java
  • ไม่มีใครเรียกMain.main()วิธีนี้ - นี่เป็นวิธีแรกในห่วงโซ่ของการโทร

อย่างไรก็ตาม ข้อมูลที่มีอยู่บางส่วนเท่านั้นที่แสดงบนหน้าจอ อย่างอื่นสามารถรับได้โดยตรงจากStackTraceElementวัตถุ



2.StackTraceElement

ตามชื่อของมันStackTraceElementคลาสถูกสร้างขึ้นเพื่อเก็บข้อมูลเกี่ยวกับ องค์ประกอบ การติดตามสแต็กนั่นคือวิธีหนึ่งในไฟล์stack trace.

คลาสนี้มีเมธอดอินสแตนซ์ดังต่อไปนี้:

วิธี คำอธิบาย
String getClassName()
ส่งกลับชื่อของชั้นเรียน
String getMethodName()
ส่งกลับชื่อของวิธีการ
String getFileName()
ส่งกลับชื่อของไฟล์ (หนึ่งไฟล์สามารถมีหลายคลาส)
int getLineNumber()
ส่งกลับหมายเลขบรรทัดในไฟล์ที่มีการเรียกใช้เมธอด
String getModuleName()
ส่งคืนชื่อของโมดูล (สามารถเป็นได้null)
String getModuleVersion()
ส่งคืนเวอร์ชันของโมดูล (สามารถเป็นได้null)

พวกเขาสามารถช่วยให้คุณได้รับข้อมูลที่ครบถ้วนมากขึ้นเกี่ยวกับ call stack ปัจจุบัน:

รหัส เอาต์พุตคอนโซล บันทึก
public class Main
{
   public static void main(String[] args)
   {
      test();
   }

   public static void test()
   {
      Thread current = Thread.currentThread();
      StackTraceElement[] methods = current.getStackTrace();

      for(StackTraceElement info: methods)
      {
         System.out.println(info.getClassName());
         System.out.println(info.getMethodName());

         System.out.println(info.getFileName());
         System.out.println(info.getLineNumber());

         System.out.println(info.getModuleName());
         System.out.println(info.getModuleVersion());
         System.out.println();
      }
   }
}
java.lang.Thread
getStackTrace
Thread.java
1606
java.base
11.0.2

Main
test
Main.java
11
null
null

Main
main
Main.java
5
null
null
ชื่อคลาส ชื่อ
เมธอด ชื่อ
ไฟล์ ชื่อ
บรรทัดหมายเลข โมดูล ชื่อ โมดูล เวอร์ชัน ชื่อคลาส ชื่อ เมธอด ไฟล์ ชื่อบรรทัด หมายเลข โมดูล ชื่อ โมดูล เวอร์ชัน คลาส ชื่อ เมธอด ไฟล์ ชื่อ บรรทัด หมายเลขโมดูล ชื่อ โมดูล เวอร์ชันโมดูล

















3. กอง

คุณรู้อยู่แล้วว่าstack traceคืออะไร แต่stack (Stack class) คืออะไร?

สแต็คเป็นโครงสร้างข้อมูลที่คุณสามารถเพิ่มองค์ประกอบและจากที่คุณสามารถดึงองค์ประกอบได้ ในการทำเช่นนั้น คุณสามารถใช้องค์ประกอบจากจุดสิ้นสุดเท่านั้น: คุณเพิ่มองค์ประกอบสุดท้ายก่อน จากนั้นจึงเพิ่มองค์ประกอบที่สองไปยังองค์ประกอบสุดท้าย ฯลฯ

ชื่อสแต็คเองบ่งบอกถึงลักษณะการทำงานนี้ เช่น วิธีที่คุณจะโต้ตอบกับปึกกระดาษ หากคุณใส่แผ่นที่ 1, 2 และ 3 ในปึก คุณต้องดึงแผ่นเหล่านั้นกลับลำดับ: แผ่นที่สามแผ่นแรก แผ่นที่สอง และแผ่นแรกเท่านั้น

Java ยังมีคลาสคอลเลกชัน Stack พิเศษที่มีชื่อและลักษณะการทำงานเหมือนกัน คลาสนี้มีพฤติกรรมหลายอย่างร่วมกับArrayListและ LinkedListแต่ก็มีวิธีการที่ใช้ลักษณะการทำงานของสแต็ก:

วิธีการ คำอธิบาย
T push(T obj)
เพิ่มobjองค์ประกอบที่ด้านบนของสแต็ก
T pop()
นำองค์ประกอบจากด้านบนของสแต็ก (ความลึกของสแต็กลดลง)
T peek()
ส่งกลับรายการที่ด้านบนสุดของสแต็ก (สแต็กไม่เปลี่ยนแปลง)
boolean empty()
ตรวจสอบว่าคอลเลกชันว่างเปล่าหรือไม่
int search(Object obj)
ค้นหาวัตถุในคอลเลกชันและส่งกลับindex

ตัวอย่าง:

รหัส เนื้อหาสแต็ก (ด้านบนของสแต็กอยู่ทางขวา)
Stack<Integer> stack = new Stack<Integer>();
stack.push(1);
stack.push(2);
stack.push(3);
int x = stack.pop();
stack.push(4);
int y = stack.peek();
stack.pop();
stack.pop();

[1]
[1, 2]
[1, 2, 3]
[1, 2]
[1, 2, 4]
[1, 2, 4]
[1, 2]
[1]

สแต็คถูกใช้ค่อนข้างบ่อยในการเขียนโปรแกรม นี่จึงเป็นคอลเลกชั่นที่มีประโยชน์



4. การแสดงสแต็กเทรซระหว่างการจัดการข้อยกเว้น

เหตุใดรายการเรียกเมธอดจึงเรียกว่าสแต็กเทรซ เนื่องจากถ้าคุณคิดว่ารายการเมธอดเป็นปึกกระดาษที่มีชื่อเมธอด เมื่อคุณเรียกเมธอดถัดไป เท่ากับคุณเพิ่มชีตที่มีชื่อเมธอดนั้นลงในสแต็ก และกระดาษแผ่นถัดไปก็วางทับบนนั้นไปเรื่อยๆ

เมื่อเมธอดสิ้นสุดลง แผ่นงานที่อยู่ด้านบนสุดของสแต็กจะถูกเอาออก คุณไม่สามารถนำแผ่นงานออกจากตรงกลางของปึกโดยไม่นำแผ่นงานที่อยู่ด้านบนออกทั้งหมด ในทำนองเดียวกัน คุณไม่สามารถยุติเมธอดระหว่างสายของการโทรโดยไม่ยุติเมธอดทั้งหมดที่เรียก

ข้อยกเว้น

การใช้สแต็คที่น่าสนใจอีกอย่างคือระหว่างการจัดการข้อยกเว้น

เมื่อเกิดข้อผิดพลาดในโปรแกรมและมีข้อผิดพลาดเกิดขึ้นข้อยกเว้นจะประกอบด้วยการติดตามสแต็ก ปัจจุบัน — อาร์เรย์ที่ประกอบด้วยรายการของวิธีการเริ่มต้น จากวิธีการหลักและสิ้นสุดด้วยวิธีการที่เกิดข้อผิดพลาด มีแม้กระทั่งบรรทัดที่เกิดข้อยกเว้น!

การติดตามสแต็กนี้ถูกจัดเก็บไว้ในข้อยกเว้นและสามารถเรียกค้นได้อย่างง่ายดายโดยใช้วิธีการต่อไปนี้:StackTraceElement[] getStackTrace()

ตัวอย่าง:

รหัส บันทึก
try
{
   // An exception may occur here
}
catch(Exception e)
{
   StackTraceElement[] methods = e.getStackTrace()
}




จับข้อยกเว้น

รับการติดตามสแต็กที่มีอยู่เมื่อเกิดข้อผิดพลาด

นี่เป็นเมธอดของThrowableคลาส ดังนั้นลูกหลานของมันทั้งหมด (เช่น ข้อยกเว้นทั้งหมด) มีgetStackTrace()เมธอด สะดวกสุด ๆ เหรอ?

แสดงการติดตามสแต็กของข้อยกเว้น

อย่างไรก็ตามThrowableคลาสมีวิธีอื่นสำหรับการทำงานกับสแต็กเทรซ ซึ่งเป็นเมธอดที่แสดงข้อมูลสแต็กเทรซทั้งหมดที่จัดเก็บไว้ในข้อยกเว้น เรียกว่าprintStackTrace().

ค่อนข้างสะดวกคุณสามารถเรียกมันได้ทุกข้อยกเว้น

ตัวอย่าง:

รหัส
try
{
   // An exception may occur here
}
catch(Exception e)
{
   e.printStackTrace();
}
เอาต์พุตคอนโซล
java.base/java.lang.Thread.getStackTrace(Thread.java:1606)
Main.test(Main.java:11)
Main.main(Main.java:5)