1. Få et stakspor

Får et stakspor

Java-programmeringssproget tilbyder mange måder for en programmør at få information om, hvad der sker i et program. Og ikke kun ord.

For eksempel, efter at C++-programmer er kompileret, bliver de til én stor fil fuld af maskinkode, og alt, hvad der er tilgængeligt for en programmør under kørsel, er adressen på den hukommelsesblok, der indeholder den maskinkode, der i øjeblikket udføres. Ikke meget, lad os sige.

Men for Java, selv efter et program er kompileret, forbliver klasser klasser, metoder og variabler forsvinder ikke, og programmøren har mange måder at få information om, hvad der sker i programmet.

Stakspor

For eksempel kan du på et tidspunkt i et programs udførelse finde ud af klassen og navnet på den metode, der i øjeblikket udføres. Og ikke kun én metode - du kan få information om hele kæden af ​​metodekald fra den nuværende metode tilbage til metoden main().

En liste, der består af den aktuelle metode, og den metode, der påkaldte den, og metode, der kaldte den, osv. kaldes en staksporing . Du kan få det med denne erklæring:

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

Du kan også skrive det som to linjer:

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

Klassens statiske currentThread()metode Threadreturnerer en reference til et Threadobjekt, som indeholder information om den aktuelle tråd, dvs. den aktuelle udførelsestråd. Du vil lære mere om tråde i niveau 17 og 18 i Java Core -questen.

Dette Threadobjekt har en getStackTrace()metode, som returnerer en række StackTraceElementobjekter, som hver indeholder information om en metode. Tilsammen danner alle disse elementer et stakspor .

Eksempel:

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

Som vi kan se i eksemplets konsoloutput, getStackTrace()returnerede metoden en række af tre elementer:

  • getStackTrace()Threadklassens metode
  • test()Mainklassens metode
  • main()Mainklassens metode

Ud fra dette stakspor kan vi konkludere, at:

  • Metoden Thread.getStackTrace()blev kaldt af Main.test()metoden på linje 11 i Main.java-filen
  • Metoden Main.test()blev kaldt af Main.main()metoden på linje 5 i Main.java-filen
  • Ingen kaldte Main.main()metoden - dette er den første metode i kæden af ​​opkald.

I øvrigt blev kun nogle af de tilgængelige oplysninger vist på skærmen. Alt andet kan fås direkte fra StackTraceElementobjektet



2.StackTraceElement

Som navnet antyder, StackTraceElementblev klassen oprettet til at gemme information om et staksporingselement , dvs. en metode i stack trace.

Denne klasse har følgende instansmetoder:

Metode Beskrivelse
String getClassName()
Returnerer navnet på klassen
String getMethodName()
Returnerer navnet på metoden
String getFileName()
Returnerer navnet på filen (én fil kan indeholde flere klasser)
int getLineNumber()
Returnerer linjenummeret i filen, hvor metoden blev kaldt
String getModuleName()
Returnerer navnet på modulet (dette kan være null)
String getModuleVersion()
Returnerer versionen af ​​modulet (dette kan være null)

De kan hjælpe dig med at få mere fuldstændig information om den aktuelle opkaldsstak:

Kode Konsoludgang Bemærk
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
klassenavn
metodenavn
filnavn
linjenummer
modulnavn
modulversion

klassenavn
metodenavn
filnavn
linjenummer
modulnavn
modulversion

klassenavn
metodenavn
filnavn
linjenummer
modulnavn
modulversion


3. Stak

Du ved allerede, hvad en stak-sporing er, men hvad er en stak (Stack-klasse)?

En stak er en datastruktur, som du kan tilføje elementer til, og hvorfra du kan hente elementer. På den måde kan du kun tage elementer fra slutningen: du tager først det sidst tilføjede, derefter det næstsidste tilføjet osv.

Selve navnestakken antyder denne adfærd, som hvordan du ville interagere med en stak papirer. Hvis du lægger ark 1, 2 og 3 i en stak, skal du hente dem i omvendt rækkefølge: først det tredje ark, derefter det andet, og først derefter det første.

Java har endda en speciel Stack Collection-klasse med samme navn og adfærd. Denne klasse deler en masse adfærd med ArrayListog LinkedList. Men det har også metoder, der implementerer stakadfærd:

Metoder Beskrivelse
T push(T obj)
Tilføjer objelementet til toppen af ​​stakken
T pop()
Tager elementet fra toppen af ​​stakken (stabeldybden falder)
T peek()
Returnerer elementet øverst i stakken (stakken ændres ikke)
boolean empty()
Kontrollerer om samlingen er tom
int search(Object obj)
Søger efter et objekt i samlingen og returnerer detsindex

Eksempel:

Kode Stakindhold (toppen af ​​stakken er til højre)
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]

Stabler bruges ret ofte i programmering. Så dette er en nyttig samling.



4. Viser et stakspor under undtagelseshåndtering

Hvorfor kaldes en liste over metodekald en staksporing ? For hvis du tænker på listen over metoder som en stak papirark med metodenavne, så når du kalder den næste metode, tilføjer du et ark med den pågældende metodes navn til stakken. Og det næste ark papir går oven i det, og så videre.

Når en metode slutter, fjernes arket øverst i stakken. Du kan ikke fjerne et ark fra midten af ​​stakken uden at fjerne alle arkene over det. På samme måde kan du ikke afslutte en metode midt i en kæde af opkald uden at afslutte alle de metoder, den har kaldt.

Undtagelser

En anden interessant brug for stakke er under undtagelseshåndtering.

Når der opstår en fejl i et program, og der fremkommer en undtagelse , indeholder undtagelsen den aktuelle stak-sporing - et array bestående af en liste over metoder, der starter, fra hovedmetoden og slutter med den metode, hvor fejlen opstod. Der er endda den linje, hvor undtagelsen blev kastet!

Dette stakspor er gemt inde i undtagelsen og kan nemt hentes fra det ved hjælp af følgende metode:StackTraceElement[] getStackTrace()

Eksempel:

Kode Bemærk
try
{
   // An exception may occur here
}
catch(Exception e)
{
   StackTraceElement[] methods = e.getStackTrace()
}




Fang undtagelsen

Hent staksporet, der fandtes, da fejlen opstod.

Dette er en metode i Throwableklassen, så alle dens efterkommere (dvs. alle undtagelser) har getStackTrace()metoden. Super praktisk, ikke?

Vis undtagelsens staksporing

Klassen har i øvrigt Throwableen anden metode til at arbejde med stakspor, en metode der viser al staksporingsinformationen gemt inde i undtagelsen. Det hedder printStackTrace().

Helt bekvemt kan du kalde det på enhver undtagelse.

Eksempel:

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