1. Få ett stack trace

Får ett stackspår

Programmeringsspråket Java erbjuder många sätt för en programmerare att få information om vad som händer i ett program. Och inte bara ord.

Till exempel, efter att C++-program har kompilerats, blir de en stor fil full av maskinkod, och allt som är tillgängligt för en programmerare vid körning är adressen till minnesblocket som innehåller maskinkoden som för närvarande exekveras. Inte mycket, låt oss säga.

Men för Java, även efter att ett program har kompilerats, förblir klasser klasser, metoder och variabler försvinner inte, och programmeraren har många sätt att få information om vad som händer i programmet.

Stack spår

Till exempel, vid ett programs körning, kan du ta reda på klassen och namnet på metoden som körs för närvarande. Och inte bara en metod - du kan få information om hela kedjan av metodanrop från den aktuella metoden tillbaka till metoden main().

En lista som består av den aktuella metoden, och metoden som anropade den, och metod som anropade den, etc. kallas stack trace . Du kan få det med detta uttalande:

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

Du kan också skriva det som två rader:

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

Klassens statiska currentThread()metod Threadreturnerar en referens till ett Threadobjekt, som innehåller information om den aktuella tråden, dvs den aktuella exekveringstråden. Du kommer att lära dig mer om trådar på nivåerna 17 och 18 i Java Core -uppdraget.

Detta Threadobjekt har en getStackTrace()metod som returnerar en array av StackTraceElementobjekt, som vart och ett innehåller information om en metod. Tillsammans bildar alla dessa element ett stackspår .

Exempel:

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

Som vi kan se i exemplets konsolutgång getStackTrace()returnerade metoden en array med tre element:

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

Från denna stackspårning kan vi dra slutsatsen att:

  • Metoden Thread.getStackTrace()anropades av Main.test()metoden på rad 11 i filen Main.java
  • Metoden Main.test()anropades av Main.main()metoden på rad 5 i filen Main.java
  • Ingen kallade Main.main()metoden - detta är den första metoden i kedjan av samtal.

Förresten, bara en del av den tillgängliga informationen visades på skärmen. Allt annat kan erhållas direkt från StackTraceElementobjektet



2.StackTraceElement

Som namnet antyder StackTraceElementskapades klassen för att lagra information om ett stackspårelement , dvs en metod i stack trace.

Den här klassen har följande instansmetoder:

Metod Beskrivning
String getClassName()
Returnerar namnet på klassen
String getMethodName()
Returnerar namnet på metoden
String getFileName()
Returnerar namnet på filen (en fil kan innehålla flera klasser)
int getLineNumber()
Returnerar radnumret i filen där metoden anropades
String getModuleName()
Returnerar namnet på modulen (detta kan vara null)
String getModuleVersion()
Returnerar versionen av modulen (detta kan vara null)

De kan hjälpa dig att få mer fullständig information om den aktuella samtalsstacken:

Koda Konsolutgång Notera
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
klassnamn
metodnamn
filnamn
radnummer
modulnamn
modulversion

klassnamn
metodnamn
filnamn
radnummer
modulnamn
modulversion

klassnamn
metodnamn filnamn
radnummer modulnamn modulversion




3. Stapla

Du vet redan vad en stackspårning är, men vad är en stack (stackklass)?

En stack är en datastruktur som du kan lägga till element i och från vilken du kan hämta element. Genom att göra det kan du bara ta element från slutet: du tar först det sista som lades till, sedan det näst sista som lades till osv.

Själva namnstacken antyder detta beteende, som hur du skulle interagera med en hög med papper. Om du lägger ark 1, 2 och 3 i en stapel måste du hämta dem i omvänd ordning: först det tredje arket, sedan det andra och först sedan det första.

Java har till och med en speciell stacksamlingsklass med samma namn och beteende. Den här klassen delar många beteenden med ArrayListoch LinkedList. Men den har också metoder som implementerar stackbeteende:

Metoder Beskrivning
T push(T obj)
Lägger till objelementet överst i stacken
T pop()
Tar elementet från toppen av stapeln (stapeldjupet minskar)
T peek()
Returnerar objektet överst i stapeln (stacken ändras inte)
boolean empty()
Kontrollerar om samlingen är tom
int search(Object obj)
Söker efter ett objekt i samlingen och returnerar dessindex

Exempel:

Koda Högens innehåll (högst upp på högen är till höger)
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]

Stackar används ganska ofta i programmering. Så det här är en användbar samling.



4. Visar ett stackspår under undantagshantering

Varför kallas en lista med metodanrop en stackspårning ? För om du tänker på listan med metoder som en bunt med pappersark med metodnamn, då när du anropar nästa metod lägger du till ett ark med den metodens namn till bunten. Och nästa pappersark går ovanpå det, och så vidare.

När en metod slutar tas arket överst i stapeln bort. Du kan inte ta bort ett ark från mitten av högen utan att ta bort alla ark ovanför det. På samma sätt kan du inte avsluta en metod mitt i en kedja av samtal utan att avsluta alla metoder som den har anropat.

Undantag

En annan intressant användning för stackar är under undantagshantering.

När ett fel inträffar i ett program och ett undantag kastas innehåller undantaget den aktuella stackspårningen — en array som består av en lista med metoder som börjar , från huvudmetoden och slutar med metoden där felet inträffade. Det finns till och med linjen där undantaget kastades!

Denna stackspårning lagras i undantaget och kan enkelt hämtas från den med följande metod:StackTraceElement[] getStackTrace()

Exempel:

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




Fånga undantaget

Hämta stackspårningen som fanns när felet uppstod.

Detta är en metod i Throwableklassen, så alla dess ättlingar (dvs alla undantag) har metoden getStackTrace(). Super bekvämt va?

Visa undantagets stackspårning

Klassen har förresten Throwableen annan metod för att arbeta med stackspårningar, en metod som visar all stackspårningsinformation som är lagrad i undantaget. Det kallas printStackTrace().

Ganska bekvämt kan du kalla det på vilket undantag som helst.

Exempel:

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