1. Einen Stack-Trace abrufen

Einen Stack-Trace abrufen

Die Programmiersprache Java bietet einem Programmierer viele Möglichkeiten, Informationen darüber zu erhalten, was in einem Programm passiert. Und nicht nur Worte.

Nachdem C++-Programme beispielsweise kompiliert wurden, werden sie zu einer großen Datei voller Maschinencode, und einem Programmierer zur Laufzeit steht nur die Adresse des Speicherblocks zur Verfügung, der den gerade ausgeführten Maschinencode enthält. Nicht viel, sagen wir mal.

Aber für Java bleiben Klassen auch nach der Kompilierung eines Programms Klassen, Methoden und Variablen verschwinden nicht und der Programmierer hat viele Möglichkeiten, Informationen darüber zu erhalten, was im Programm passiert.

Stack-Trace

Beispielsweise können Sie zum Zeitpunkt der Programmausführung die Klasse und den Namen der gerade ausgeführten Methode ermitteln. Und nicht nur eine Methode – Sie können Informationen über die gesamte Kette von Methodenaufrufen von der aktuellen Methode zurück zur main()Methode erhalten.

Eine Liste, die aus der aktuellen Methode und der Methode, die sie aufgerufen hat, und der Methode, die diese aufgerufen hat usw. besteht, wird als Stack-Trace bezeichnet . Sie können es mit dieser Aussage erhalten:

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

Sie können es auch in zwei Zeilen schreiben:

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

Die statische currentThread()Methode der ThreadKlasse gibt einen Verweis auf ein ThreadObjekt zurück, das Informationen über den aktuellen Thread, also den aktuellen Ausführungsthread, enthält. Mehr über Threads erfahren Sie in den Levels 17 und 18 der Java Core- Quest.

Dieses ThreadObjekt verfügt über eine getStackTrace()Methode, die ein Array von StackTraceElementObjekten zurückgibt, von denen jedes Informationen über eine Methode enthält. Zusammengenommen bilden alle diese Elemente einen Stacktrace .

Beispiel:

Code
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);
   }
}
Konsolenausgabe
java.base/java.lang.Thread.getStackTrace(Thread.java:1606)
Main.test(Main.java:11)
Main.main(Main.java:5)

Wie wir in der Konsolenausgabe des Beispiels sehen können, hat die getStackTrace()Methode ein Array aus drei Elementen zurückgegeben:

  • getStackTrace()Methode der ThreadKlasse
  • test()Methode der MainKlasse
  • main()Methode der MainKlasse

Aus diesem Stack-Trace können wir Folgendes schließen:

  • Die Methode wurde von der Methode in Zeile 11 der Datei Main.java Thread.getStackTrace()aufgerufenMain.test()
  • Die Methode wurde von der Methode in Zeile 5 der Datei Main.java Main.test()aufgerufenMain.main()
  • Niemand hat die Main.main()Methode aufgerufen – dies ist die erste Methode in der Aufrufkette.

Übrigens wurden nur einige der verfügbaren Informationen auf dem Bildschirm angezeigt. Alles Weitere kann direkt vom StackTraceElementObjekt bezogen werden



2.StackTraceElement

Wie der Name schon sagt, StackTraceElementwurde die Klasse erstellt, um Informationen über ein Stack-Trace- Element, also eine Methode im , zu speichern stack trace.

Diese Klasse verfügt über die folgenden Instanzmethoden:

Methode Beschreibung
String getClassName()
Gibt den Namen der Klasse zurück
String getMethodName()
Gibt den Namen der Methode zurück
String getFileName()
Gibt den Namen der Datei zurück (eine Datei kann mehrere Klassen enthalten)
int getLineNumber()
Gibt die Zeilennummer in der Datei zurück, in der die Methode aufgerufen wurde
String getModuleName()
Gibt den Namen des Moduls zurück (dies kann sein null)
String getModuleVersion()
Gibt die Version des Moduls zurück (dies kann sein null)

Sie können Ihnen helfen, umfassendere Informationen über den aktuellen Aufrufstapel zu erhalten:

Code Konsolenausgabe Notiz
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
Klassenname
Methodenname
Dateiname
Zeilennummer
Modulname
Modulversion

Klassenname
Methodenname
Dateiname
Zeilennummer
Modulname
Modulversion

Klassenname
Methodenname
Dateiname
Zeilennummer
Modulname
Modulversion


3. Stapeln

Sie wissen bereits, was ein Stack-Trace ist, aber was ist ein Stack (Stack-Klasse)?

Ein Stapel ist eine Datenstruktur, zu der Sie Elemente hinzufügen und aus der Sie Elemente abrufen können. Dabei können Sie nur Elemente vom Ende übernehmen: Zuerst nehmen Sie das zuletzt hinzugefügte, dann das vorletzte hinzugefügte usw.

Der Name „Stack“ selbst deutet auf dieses Verhalten hin, etwa wie man mit einem Stapel Papiere interagieren würde. Wenn Sie die Blätter 1, 2 und 3 auf einen Stapel legen, müssen Sie sie in umgekehrter Reihenfolge entnehmen: zuerst das dritte Blatt, dann das zweite und erst dann das erste.

Java verfügt sogar über eine spezielle Stack-Sammlungsklasse mit demselben Namen und demselben Verhalten. Diese Klasse teilt viele Verhaltensweisen mit ArrayListund LinkedList. Es gibt aber auch Methoden, die das Stack-Verhalten implementieren:

Methoden Beschreibung
T push(T obj)
Fügt das objElement oben im Stapel hinzu
T pop()
Nimmt das Element von der Oberseite des Stapels (die Stapeltiefe verringert sich)
T peek()
Gibt das Element an der Spitze des Stapels zurück (der Stapel ändert sich nicht)
boolean empty()
Überprüft, ob die Sammlung leer ist
int search(Object obj)
Sucht nach einem Objekt in der Sammlung und gibt dieses zurückindex

Beispiel:

Code Stapelinhalt (die Oberseite des Stapels befindet sich rechts)
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]

Stacks werden in der Programmierung häufig verwendet. Das ist also eine nützliche Sammlung.



4. Anzeigen eines Stack-Trace während der Ausnahmebehandlung

Warum wird eine Liste von Methodenaufrufen als Stack-Trace bezeichnet ? Denn wenn Sie sich die Liste der Methoden als einen Stapel Blätter Papier mit Methodennamen vorstellen, fügen Sie beim Aufruf der nächsten Methode ein Blatt mit dem Namen dieser Methode zum Stapel hinzu. Und das nächste Blatt Papier kommt darüber und so weiter.

Wenn eine Methode endet, wird das oberste Blatt des Stapels entfernt. Sie können ein Blatt nicht aus der Mitte des Stapels entfernen, ohne alle darüber liegenden Blätter zu entfernen. Ebenso können Sie eine Methode nicht mitten in einer Aufrufkette beenden, ohne alle aufgerufenen Methoden zu beenden.

Ausnahmen

Eine weitere interessante Verwendung von Stacks ist die Ausnahmebehandlung.

Wenn in einem Programm ein Fehler auftritt und eine Ausnahme ausgelöst wird , enthält die Ausnahme den aktuellen Stack-Traceein Array bestehend aus einer Liste von Methoden, beginnend mit der Hauptmethode und endend mit der Methode, bei der der Fehler aufgetreten ist. Es gibt sogar die Zeile, in der die Ausnahme ausgelöst wurde!

Dieser Stack-Trace wird in der Ausnahme gespeichert und kann mit der folgenden Methode einfach daraus abgerufen werden:StackTraceElement[] getStackTrace()

Beispiel:

Code Notiz
try
{
   // An exception may occur here
}
catch(Exception e)
{
   StackTraceElement[] methods = e.getStackTrace()
}




Fangen Sie die Ausnahme ab.

Rufen Sie den Stack-Trace ab, der vorhanden war, als der Fehler auftrat.

Dies ist eine Methode der ThrowableKlasse, daher verfügen alle ihre Nachkommen (dh alle Ausnahmen) über die getStackTrace()Methode. Super praktisch, oder?

Zeigen Sie den Stacktrace der Ausnahme an

Übrigens Throwableverfügt die Klasse über eine weitere Methode zum Arbeiten mit Stack-Traces, eine Methode, die alle in der Ausnahme gespeicherten Stack-Trace-Informationen anzeigt. Es heißt printStackTrace().

Ganz praktisch ist, dass Sie es bei jeder Ausnahme aufrufen können.

Beispiel:

Code
try
{
   // An exception may occur here
}
catch(Exception e)
{
   e.printStackTrace();
}
Konsolenausgabe
java.base/java.lang.Thread.getStackTrace(Thread.java:1606)
Main.test(Main.java:11)
Main.main(Main.java:5)