Introduktion til Java 9 StackWalking API

1. Introduktion

I denne hurtige artikel vil vi se på Java 9s StackWalking API.

Den nye funktionalitet giver adgang til en Strøm af StackFrames, der giver os mulighed for nemt at gennemse stack i både direkte og gøre god brug af den kraftfulde Strøm API i Java 8.

2. Fordele ved en StackWalker

I Java 8 er Kan kastes :: getStackTrace og Tråd :: getStackTrace returnerer en matrix af StackTraceElements. Uden en masse manuel kode var der ingen måde at kassere de uønskede rammer og kun beholde dem, vi er interesseret i.

Ud over dette er den Tråd :: getStackTrace kan returnere en delvis staksporing. Dette skyldes, at specifikationen gør det muligt for VM-implementeringen at udelade nogle stakrammer af hensyn til ydeevnen.

I Java 9, bruger gå() metode til StackWalker, vi kan krydse et par rammer, som vi er interesserede i eller den komplette staksporing.

Selvfølgelig er den nye funktionalitet trådsikker; dette gør det muligt for flere tråde at dele en enkelt StackWalker eksempel for at få adgang til deres respektive stakke.

Som beskrevet i JEP-259 vil JVM blive forbedret for at give effektiv doven adgang til yderligere stabelrammer, når det er nødvendigt.

3. StackWalker i aktion

Lad os starte med at oprette en klasse, der indeholder en kæde af metodeopkald:

offentlig klasse StackWalkerDemo {public void methodOne () {this.methodTwo (); } public void methodTwo () {this.methodThree (); } public void methodThree () {// stack walking code}}

3.1. Fang hele staksporet

Lad os gå videre og tilføje nogle stack walking-koder:

public void methodThree () {List stackTrace = StackWalker.getInstance () .walk (dette :: walkExample); } 

Det StackWalker :: gå metode accepterer en funktionel reference, opretter en Strøm af StackFrames for den aktuelle tråd, anvender funktionen til Strømog lukker Strøm.

Lad os nu definere StackWalkerDemo :: walkExample metode:

offentlig liste walkExample (Stream stackFrameStream) {return stackFrameStream.collect (Collectors.toList ()); }

Denne metode samler simpelthen StackFrames og returnerer det som en Liste. For at teste dette eksempel skal du køre en JUnit-test:

@Test offentlig ugyldighed giveStalkWalker_whenWalkingTheStack_thenShowStackFrames () {new StackWalkerDemo (). MethodOne (); }

Den eneste grund til at køre det som en JUnit-test er at have flere rammer i vores stak:

klasse com.baeldung.java9.stackwalker.StackWalkerDemo # methodThree, Line 20 class com.baeldung.java9.stackwalker.StackWalkerDemo # methodTwo, Line 15 class com.baeldung.java9.stackwalker.StackWalkerDemo # methodOneeld, line 11. com. java9.stackwalker .StackWalkerDemoTest # giveStalkWalker_whenWalkingTheStack_thenShowStackFrames, Line 9 klasse org.junit.runners.model.FrameworkMethod $ 1 # runReflectiveCall, Line 50 klasse org.junit.internal.runners.model.Rective.Rective.Rective.Rective.Rective.Rective.Reflective.Runers.model.Reflective.Runers.model.Reflective.Runers.model. frames ... class org.junit.runners.ParentRunner # run, Line 363 class org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference # run, Line 86 ... more org.eclipse frames ... class org. eclipse.jdt.internal.junit.runner.RemoteTestRunner # main, linje 192

I hele stakksporingen er vi kun interesseret i top fire rammer. Det resterende rammer fra org.junit og org.formørkelse er intet andet end støjrammer.

3.2. Filtrering af StackFrames

Lad os forbedre vores stack walking-kode og fjerne støj:

offentlig liste walkExample2 (Stream stackFrameStream) {return stackFrameStream .filter (f -> f.getClassName (). indeholder ("com.baeldung")) .collect (Collectors.toList ()); }

Brug af kraften i Strøm API, vi holder kun de rammer, som vi er interesseret i. Dette fjerner støj og efterlader de øverste fire linjer i stakloggen:

klasse com.baeldung.java9.stackwalker.StackWalkerDemo # methodThree, Line 27 class com.baeldung.java9.stackwalker.StackWalkerDemo # methodTwo, Line 15 class com.baeldung.java9.stackwalker.StackWalkerDemo # methodOneeld, line 11. com. java9.stackwalker .StackWalkerDemoTest # giveStalkWalker_whenWalkingTheStack_thenShowStackFrames, Line 9

Lad os nu identificere JUnit-testen, der startede opkaldet:

public String walkExample3 (Stream stackFrameStream) {return stackFrameStream .filter (frame -> frame.getClassName () .contains ("com.baeldung") && frame.getClassName (). endsWith ("Test")) .findFirst () .map (f -> f.getClassName () + "#" + f.getMethodName () + ", Line" + f.getLineNumber ()). orElse ("Ukendt opkald"); }

Bemærk venligst, at her er vi kun interesseret i en enkelt StackFrame, som er kortlagt til en Snor. Outputtet er kun den linje, der indeholder StackWalkerDemoTest klasse.

3.3. Optagelse af refleksionsrammer

For at fange refleksionsrammerne, som er skjult som standard, er StackWalker skal konfigureres med en ekstra mulighed SHOW_REFLECT_FRAMES:

Liste stackTrace = StackWalker .getInstance (StackWalker.Option.SHOW_REFLECT_FRAMES). Gang (dette :: walkExample);

Brug af denne mulighed, alle refleksionsrammer inklusive Method.invoke () og Constructor.newInstance () bliver fanget:

com.baeldung.java9.stackwalker.StackWalkerDemo # methodThree, Line 40 com.baeldung.java9.stackwalker.StackWalkerDemo # methodTwo, Line 16 com.baeldung.java9.stackwalker.StackWalkerDemo # methodOne, Line 12 com.baeldung.jal. StackWalkerDemoTest # giveStalkWalker_whenWalkingTheStack_thenShowStackFrames, Line 9 jdk.internal.reflect.NativeMethodAccessorImpl # invoke0, Line -2 jdk.internal.reflect.NativeMethodAccessorImpl # invoke.cod. #invoke, Line 547 org.junit.runners.model.FrameworkMethod $ 1 # runReflectiveCall, Line 50 ... eclipse and junit frames ... org.eclipse.jdt.internal.junit.runner.RemoteTestRunner # main, Line 192

Som vi kan se, er jdk.intern rammer er de nye, der er fanget af SHOW_REFLECT_FRAMES mulighed.

3.4. Indfangning af skjulte rammer

Ud over refleksionsrammerne kan en JVM-implementering vælge at skjule implementeringsspecifikke rammer.

Disse rammer er dog ikke skjult for StackWalker:

Kan køres r = () -> {Liste stackTrace2 = StackWalker .getInstance (StackWalker.Option.SHOW_HIDDEN_FRAMES). Gang (dette :: walkExample); printStackTrace (stackTrace2); }; r.run ();

Bemærk, at vi tildeler en lambda-reference til a Kan køres i dette eksempel. Den eneste grund er, at JVM vil skabe nogle skjulte rammer til lambda-udtrykket.

Dette er tydeligt synligt i stakksporingen:

com.baeldung.java9.stackwalker.StackWalkerDemo # lambda $ 0, Line 47 com.baeldung.java9.stackwalker.StackWalkerDemo $$ Lambda $ 39/924477420 # run, Line -1 com.baeldung.java9.stackwalker.StackWalkerDemo # 50Th com.baeldung.java9.stackwalker.StackWalkerDemo # methodTwo, Line 16 com.baeldung.java9.stackwalker.StackWalkerDemo # methodOne, Line 12 com.baeldung.java9.stackwalker .StackWalkerDemoTest # giveStalkWalkerStack.Wind_Stackwalker invoke0, Line -2 jdk.internal.reflect.NativeMethodAccessorImpl # invoke, Line 62 jdk.internal.reflect.DelegatingMethodAccessorImpl # invoke, Line 43 java.lang.reflect.Method # invoke, Line 547 org.junit.runners.model.FrameworkM $ 1 # runReflectiveCall, Line 50 ... junit og eclipse frames ... org.eclipse.jdt.internal.junit.runner.RemoteTestRunner # main, Line 192

De to øverste rammer er lambda proxy-rammer, som JVM oprettede internt. Det er værd at bemærke, at de refleksionsrammer, som vi fangede i det foregående eksempel, stadig bevares VIS_HIDDEN_FRAMES mulighed. Dette er fordi VIS_HIDDEN_FRAMES er et supersæt af SHOW_REFLECT_FRAMES.

3.5. Identificering af opkaldsklassen

Muligheden RETAIN_CLASS_REFERENCE sælger genstanden til Klasse i alle StackFrames gik forbi StackWalker. Dette giver os mulighed for at kalde metoderne StackWalker :: getCallerClass og StackFrame :: getDeclaringClass.

Lad os identificere opkaldsklassen ved hjælp af StackWalker :: getCallerClass metode:

public void findCaller () {Class caller = StackWalker .getInstance (StackWalker.Option.RETAIN_CLASS_REFERENCE) .getCallerClass (); System.out.println (caller.getCanonicalName ()); }

Denne gang kalder vi denne metode direkte fra en separat JUnit-test:

@Test public void giveStalkWalker_whenInvokingFindCaller_thenFindCallingClass () {new StackWalkerDemo (). FindCaller (); }

Resultatet af caller.getCanonicalName (), vil være:

com.baeldung.java9.stackwalker.StackWalkerDemoTest

Bemærk, at StackWalker :: getCallerClass bør ikke kaldes fra metoden i bunden af ​​stakken. som det vil resultere i IllegalCallerException bliver kastet.

4. Konklusion

Med denne artikel har vi set, hvor let det er at håndtere StackFrames bruger kraften i StackWalker kombineret med Strøm API.

Der er selvfølgelig forskellige andre funktioner, vi kan udforske - som at springe, droppe og begrænse StackFrames. Den officielle dokumentation indeholder et par solide eksempler på yderligere brugssager.

Og som altid kan du få den komplette kildekode til denne artikel på GitHub.


$config[zx-auto] not found$config[zx-overlay] not found