Bevezetés a Java 9 StackWalking API-ba

1. Bemutatkozás

Ebben a rövid cikkben áttekintjük a Java 9 StackWalking API-ját.

Az új funkció hozzáférést biztosít a Folyam nak,-nek StackFrames, amely lehetővé teszi számunkra, hogy könnyedén böngésszünk a veremben mind közvetlenül, mind pedig a nagy teljesítményűek kihasználásával Folyam API Java 8-ban.

2. A. Előnyei StackWalker

A Java 8-ban a Dobható :: getStackTrace és Téma :: getStackTrace tömböt ad vissza StackTraceElements. Sok kézi kód nélkül nem volt mód elvetni a nem kívánt kereteket, és csak azokat megtartani, amelyek érdekeltek.

Ezen felül a Téma :: getStackTrace részleges verem nyomot adhat vissza. Ez azért van, mert a specifikáció lehetővé teszi, hogy a virtuális gép megvalósítása kihagyjon néhány veremkeretet a teljesítmény érdekében.

A Java 9-ben használni a séta() módszere StackWalker, bejárhatunk néhány olyan keretet, amely érdekel vagy a teljes verem nyom.

Természetesen az új funkcionalitás szálbiztos; ez lehetővé teszi több szál egyetlen megosztását StackWalker például a megfelelő halmaik eléréséhez.

Amint azt a JEP-259 leírja, a JVM-et tovább fogják fejleszteni, hogy szükség esetén hatékony lusta hozzáférést biztosítson további veremkeretekhez.

3. StackWalker akcióban

Kezdjük egy osztály létrehozásával, amely metódushívások láncolatát tartalmazza:

public class StackWalkerDemo {public void methodOne () {this.methodTwo (); } public void methodTwo () {this.methodThree (); } public void methodThree () {// verem gyalogos kód}}

3.1. Rögzítse a teljes verem nyomot

Menjünk előre, és adjunk hozzá néhány verem-járási kódot:

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

A StackWalker :: walk módszer elfogad funkcionális referenciát, létrehoz egy Folyam nak,-nek StackFrames az aktuális szálra a függvényt alkalmazza a Folyam, és bezárja a Folyam.

Most definiáljuk a StackWalkerDemo :: walkExample módszer:

public List walkExample (Stream stackFrameStream) {return stackFrameStream.collect (Collectors.toList ()); }

Ez a módszer egyszerűen összegyűjti a StackFrames és a-ként adja vissza Lista. A példa teszteléséhez futtasson egy JUnit tesztet:

@Test public void giveStalkWalker_whenWalkingTheStack_thenShowStackFrames () {new StackWalkerDemo (). MethodOne (); }

Az egyetlen oka annak, hogy JUnit tesztként futtassa, az, hogy több keret legyen a veremben:

class com.baeldung.java9.stackwalker.StackWalkerDemo # methodThree, 20. sor Class com.baeldung.java9.stackwalker.StackWalkerDemo # methodTwo, Line 15 class com.baeldung.java9.stackwalker.StackWalkerDemo # method.ba, Line 11 class com. java9.stackwalker .StackWalkerDemoTest # giveStalkWalker_whenWalkingTheStack_thenShowStackFrames, 9. sor org.junit.runners.model.FrameworkMethod $ 1 # runReflectiveCall, 50. sor org.junit.internel.runners ... run 50. orgun.Junit.internel.runners keretek ... class org.junit.runners.ParentRunner # run, 363. sor eclipse.jdt.internal.junit.runner.RemoteTestRunner # main, 192. sor

A verem teljes nyomában csak a felső négy keret érdekel. A maradék keretek az org.junit és org.fogyatkozás nem mások, mint zajkeretek.

3.2. A. Szűrése StackFrames

Fejlesszük veremjárási kódunkat és távolítsuk el a zajt:

public List walkExample2 (Stream stackFrameStream) {return stackFrameStream .filter (f -> f.getClassName (). tartalmaz ("com.baeldung")) .collect (Collectors.toList ()); }

Kihasználva a Folyam API, csak azokat a kereteket tartjuk meg, amelyek érdekelnek minket. Ez kitisztítja a zajt, így a felső négy sor a veremnaplóban marad:

class com.baeldung.java9.stackwalker.StackWalkerDemo # methodThree, 27. sor class com.baeldung.java9.stackwalker.StackWalkerDemo # methodTwo, Line 15 class com.baeldung.java9.stackwalker.StackWalkerDemo # method.ba, Line 11 class com. java9.stackwalker .StackWalkerDemoTest # giveStalkWalker_whenWalkingTheStack_thenShowStackFrames, 9. sor

Most azonosítsuk a hívást kezdeményező JUnit tesztet:

public String walkExample3 (Stream stackFrameStream) {return stackFrameStream .filter (frame -> frame.getClassName () .contains ("com.baeldung") && frame.getClassName (). endWith ("Test")) .findFirst () .map (f -> f.getClassName () + "#" + f.getMethodName () + ", Line" + f.getLineNumber ()) .orElse ("Ismeretlen hívó"); }

Felhívjuk figyelmét, hogy itt csak egyetlenegy anyag érdekel StackFrame, amelyet leképeznek a Húr. A kimenet csak az a sor lesz, amely tartalmazza StackWalkerDemoTest osztály.

3.3. A tükörképek rögzítése

Az alapértelmezés szerint rejtett reflexiós keretek rögzítéséhez a StackWalker további opcióval kell konfigurálni SHOW_REFLECT_FRAMES:

List stackTrace = StackWalker .getInstance (StackWalker.Option.SHOW_REFLECT_FRAMES) .walk (this :: walkExample);

Ezzel az opcióval az összes reflexiókeretet beleértve Method.invoke () és Constructor.newInstance () elfogják:

com.baeldung.java9.stackwalker.StackWalkerDemo # methodThree, 40. sor com.baeldung.java9.stackwalker.StackWalkerDemo # methodTwo, 16. sor com.baeldung.java9.stackwalker.StackWalkerDemo # methodOne, 12. sor com.baeldung. StackWalkerDemoTest # giveStalkWalker_whenWalkingTheStack_thenShowStackFrames, 9. sor jdk.internal.reflect.NativeMethodAccessorImpl # invoke0, -2. Sor jdk.internal.reflect.NativeMethodAccessorImpl # invoke #invoke, 547. sor org.junit.runners.model.FrameworkMethod $ 1 # runReflectiveCall, Line 50 ... napfogyatkozás és junit keretek ... org.eclipse.jdt.internal.junit.runner.RemoteTestRunner # main, 192 sor

Mint láthatjuk, a jdk.belső keretek az újak, amelyeket elfogott SHOW_REFLECT_FRAMES választási lehetőség.

3.4. Rejtett keretek rögzítése

A reflexiós keretek mellett egy JVM implementáció eldöntheti a megvalósítás specifikus kereteinek elrejtését.

Ezek a keretek azonban nincsenek elrejtve a StackWalker:

Futható r = () -> {List stackTrace2 = StackWalker .getInstance (StackWalker.Option.SHOW_HIDDEN_FRAMES) .walk (this :: walkExample); printStackTrace (stackTrace2); }; r.run ();

Ne feledje, hogy lambda hivatkozást rendelünk az a-hoz Futható ebben a példában. Az egyetlen ok az, hogy a JVM létrehoz néhány rejtett keretet a lambda kifejezéshez.

Ez jól látható a verem nyomában:

com.baeldung.java9.stackwalker.StackWalkerDemo # lambda $ 0, 47. sor com.baeldung.java9.stackwalker.StackWalkerDemo $$ Lambda $ 39/924477420 # run, -1. sor com.baeldung.java9.stackwalker.StackWalkerDemo # method com.baeldung.java9.stackwalker.StackWalkerDemo # methodTwo, 16. sor com.baeldung.java9.stackwalker.StackWalkerDemo # methodOne, 12. sor com.baeldung.java9.stackwalker .StackWalkerDemoTest # giveStalkWalker_howWaterWalker invoke0, -2 vonal jdk.internal.reflect.NativeMethodAccessorImpl # invoke, 62. sor jdk.internal.reflect.DelegatingMethodAccessorImpl # invoke, 43. sor java.lang.reflect.Method # invoke, 547. sor org.junit.runners.model $ 1 # runReflectiveCall, 50. sor ... junit és eclipse keretek ... org.eclipse.jdt.internal.junit.runner.RemoteTestRunner # main, 192 sor

A felső két keret a lambda proxy keret, amelyet a JVM belsőleg készített. Érdemes megjegyezni, hogy az előző példában rögzített reflexiós keretek továbbra is megmaradnak SHOW_HIDDEN_FRAMES választási lehetőség. Ez azért van, mert SHOW_HIDDEN_FRAMES a szuperhalmaza SHOW_REFLECT_FRAMES.

3.5. A hívóosztály azonosítása

Az opció RETAIN_CLASS_REFERENCE kiskereskedelmi objektumát Osztály az összes StackFrames elsétált a StackWalker. Ez lehetővé teszi számunkra a módszerek meghívását StackWalker :: getCallerClass és StackFrame :: getDeclaringClass.

Azonosítsuk a hívó osztályt a StackWalker :: getCallerClass módszer:

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

Ezúttal ezt a módszert közvetlenül egy külön JUnit tesztből hívjuk meg:

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

A kimenet caller.getCanonicalName (), lesz:

com.baeldung.java9.stackwalker.StackWalkerDemoTest

Felhívjuk figyelmét, hogy a StackWalker :: getCallerClass nem szabad a verem alján található metódusból meghívni. mivel ez azt eredményezi IllegalCallerException dobják.

4. Következtetés

Ezzel a cikkel láttuk, milyen könnyű kezelni StackFrames kihasználva a StackWalker kombinálva a Folyam API.

Természetesen számos más funkcióval is foglalkozhatunk - ilyen például az ugrás, a dobás és a korlátozás StackFrames. A hivatalos dokumentáció néhány szilárd példát tartalmaz a további felhasználási esetekre.

És, mint mindig, a cikk teljes forráskódját a GitHubon töltheti le.