“java 9 Stack walking API that allows laziness and frame filtering, supports short walks that stop at a frame matching given criteria, and also supports long walks that traverse the entire stack”

Before java 9 we can get stack trace by calling getStacktrace method of throwable class in catch clause or instantiating throwable class and use print stack trace.

Example:

In this exampe we are trying to read tmp file which does not exists at given location so it will throw exception.

public void printStackTrace(){
        try{
            BufferedReader bufferedReader = new BufferedReader(new FileReader(new File("C:\\tmp.txt")));
            bufferedReader.readLine();
            bufferedReader.close();
            //First way
            StackTraceElement [] stackTraceElements = new Throwable().getStackTrace();
        }catch (Throwable e){
            //second way;
            StackTraceElement [] stackTraceElements = e.getStackTrace();
            for(StackTraceElement element : stackTraceElements){
                System.out.println(element.toString());
            }
            //third way
            //e.printStackTrace();
        }
    }

Output:

java.base/java.io.FileInputStream.open0(Native Method)
java.base/java.io.FileInputStream.open(FileInputStream.java:196)
java.base/java.io.FileInputStream.<init>(FileInputStream.java:139)
java.base/java.io.FileReader.<init>(FileReader.java:72)
javadeveloperzone.base/com.example.WalkerApiDemo.printStackTrace(WalkerApiDemo.java:34)
javadeveloperzone.base/com.example.WalkerApiDemo.main(WalkerApiDemo.java:51)

As we can see it will print whole stack trace except the hidden one, it’s difficult to find a few frames from that or if is also displaying actual class name where this method is declared. To overcome these type of problem java 9 comes with one handy feature called Stack Walking Api under JEP-259.

stack-walking API that allows laziness and frame filtering, supports short walks that stop at a frame matching given criteria and also supports long walks that traverse the entire stack.

StackWalker class is the heart of new stack walking API.lets discuss detail about it.

How to instantiate StackWalker class?

Static method getInstance method is used to get the StackWalker.There is four version available of this method.

private static final int DEFAULT_STACK_WALKER=1;
    private static final int OPTION_STACK_WALKER=2;
    private static final int OPTION_SET_STACK_WALKER=3;
    private static final int OPTION_SET_DEPTH_STACK_WALKER=4;
    public StackWalker getStackWalker(int option){
        StackWalker walker = null;
        switch (option){
            case DEFAULT_STACK_WALKER:
                walker = StackWalker.getInstance();
                break;
            case OPTION_STACK_WALKER:
                //3 options available
                //1 RETAIN_CLASS_REFERENCE
                //2 SHOW_REFLECT_FRAMES
                //3 SHOW_HIDDEN_FRAMES
                walker = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);
                break;
            case OPTION_SET_STACK_WALKER:
                walker = StackWalker.getInstance(Set.of(StackWalker.Option.RETAIN_CLASS_REFERENCE));
                break;
            case OPTION_SET_DEPTH_STACK_WALKER:
                walker = StackWalker.getInstance(Set.of(StackWalker.Option.RETAIN_CLASS_REFERENCE),32);
                break;
        }
        return walker;
    }

Other than getInstance method there are 3 other method available in stackwalker class to get the relavant information and perform certain actions.

1 ) void forEach (Consumer<? super StackWalker.StackFrame> action)

Performs the given action on each element of StackFrame stream of the current thread, traversing from the top frame of the stack, which is the method calling this forEach method.

Example :

public void stackWalkerForEach(){
        StackWalker walker = getStackWalker(DEFAULT_STACK_WALKER);
        walker.forEach(System.out::println);
    }

2 ) Class<?> getCallerClass ()

Gets the Class object of the caller who invoked the method that invoked getCallerClass.

Example : 

public void stackWalkerCallerClass(){
        StackWalker walker = getStackWalker(OPTION_STACK_WALKER);
        Class<?> callerClass = walker.getCallerClass();
        System.out.println("Caller class name : "+callerClass.getName());
    }

Output:

Caller class name : com.example.WalkerApiDemo

Note : We must instantiate StackWalker class with RETAIN_CLASS_REFERENCE option otherwise it will throw exception.

Example:

public void stackWalkerCallerClass(){
        StackWalker walker = getStackWalker(DEFAULT_STACK_WALKER);
        Class<?> callerClass = walker.getCallerClass();
        System.out.println("Caller class name : "+callerClass.getName());
    }

 Output:

Exception in thread "main" java.lang.UnsupportedOperationException: This stack walker does not have 
RETAIN_CLASS_REFERENCE access
  at java.base/java.lang.StackWalker.getCallerClass(StackWalker.java:551)
  at javadeveloperzone.base/com.example.WalkerApiDemo.stackWalkerCallerClass(WalkerApiDemo.java:86)
  at javadeveloperzone.base/com.example.WalkerApiDemo.main(WalkerApiDemo.java:95)

3 ) <T> T walk (Function<? super Stream<StackWalker.StackFrame>,? extends T> function)

Applies the given function to the stream of StackFrames for the current thread, traversing from the top frame of the stack, which is the method calling this walk method.

Example:

In this example we use limit method to restrict top 2 stack frames.

public void accessStackFrames(){
        try{
            BufferedReader bufferedReader = new BufferedReader(new FileReader(new File("C:\\tmp.txt")));
            bufferedReader.readLine();
            bufferedReader.close();
        }catch (Throwable e){
            //e.printStackTrace();
            List<StackWalker.StackFrame> frames = getStackWalker(DEFAULT_STACK_WALKER).walk(s ->
                    s.limit(2)
                            .collect(Collectors.toList()));
            for(StackWalker.StackFrame frame : frames){
                System.out.println(frame);
            }
        }
    }

Output:

javadeveloperzone.base/com.example.WalkerApiDemo.accessStackFrames(WalkerApiDemo.java:24)
javadeveloperzone.base/com.example.WalkerApiDemo.main(WalkerApiDemo.java:95)

Refer JEP-259 and StackWalker links for more details.

Click here to download source code

Was this post helpful?
Let us know, if you liked the post. Only in this way, we can improve us.
Yes
No

Leave a Reply

Your email address will not be published. Required fields are marked *