It’s time to dive in deeper into Java 9 and discover some more features it has to offer. This time, we’ve decided to focus on the StackWalker.
In the following post we’ll go over Java Enhancement Proposal (JEP) 259: Stack-Walking API, check out what’s StackWalking is all about and of course, enjoy some of our all time favorite references from Star Wars. Get ready to reach point five past lightspeed.
Stack-Skywalker Here to Rescue You
You already know we count back the days to the launch of Java 9, and one of our pastime activities is going over the JEPs proposed to target JDK 9. We’ve already came across some interesting new features, that include some that might change the way you code, and some that you might have never heard about.
We admit it, JEP 259 caught our eyes due to its name: Stack-Walking API. Sure, walking across the stack is an interesting concept, but it’s the vague reference to Star Wars that really got us exploring it. It was a smart decision, since we found yet another cool feature that’s about to be part of Java 9.
Walking Along the Stack
Even if you’ve never heard of the StackWalker class, it’s pretty self-explanatory from its name alone. Yup, it walks along the stack. But it’s much more than just that. It’s the first time we get to have an official Java way to process stack traces, versus treating them as plain text.
To be more specific, this class includes methods that go over the stack and provide us an overview of the current thread at any point we desire. It’s somewhat of a snapshot to a certain stack trace we’re interested in.
There are a few methods we can use in order to capture the information we want in the stack, such as:
- forEach: Performs the given action on each element of StackFrame stream of the current thread
- getInstance(): Returns a StackWalker instance
- walk: Applies the given function to the stream of StackFrames for the current thread
For example, when we use the walk method in the StackWalker class, it opens a sequential stream of StackFrames for the current thread and then applies the given function to the StackFrame stream. StackFrame is the object that represents a method invocation returned by StackWalker.
The stream is the one in charge of reporting the stack frame elements in order, starting from the top most frame. The top frame represents the execution point at which the stack was generated, and the stream continues to report until it reach the bottom most frame.
The StackFrame stream is closed when the walk method returns, and any attempt to reuse it will lead to an IllegalStateException being thrown. Speaking of it, according to a recent research of ours, IllegalStateException is the 5th most popular exception that is thrown in production.
Back to StackWalker – it’s thread-safe, meaning that multiple threads can share a single StackWalker object to cross its own stack.
In the following example we want to find the first 10 calling frames in the method, first skipping those frames whose declaring class is in package com.foo:
List<StackFrame> frames = StackWalker.getInstance().walk(s -> s.dropWhile(f -> f.getClassName().startsWith("com.foo.")) .limit(10) .collect(Collectors.toList()));
We can see how to use the StackWalker.getInstance method, specifying the stack frame information it can access. This method takes a Function accepting a Stream<StackFrame>, rather than returning a Stream<StackFrame> and allowing the caller to directly manipulate the stream.
Stack-Walking in Java 9
Why is it so important? Well, while there are some APIs that provide access to a thread’s stack, they require the VM to capture a snapshot of the entire stack and return the information representing it. This means that if the caller is only interested in the top few frames on the stack, it will still require it to go through all of the frames.
Among these APIs you’ll be able to find Throwable::getStackTrace and Thread::getStackTrace, that return an array of StackTraceElement objects. These objects contain the class name and method name of each stack-trace element. However, the methods in these APIs return an array of StackTraceElement objects, which contain class and method names, but not the actual Class instances.
Oracle itself points out that for applications that are interested in the entire stack, the current specification allows the VM implementation to omit some frames in the stack for performance. In other words, Thread::getStackTrace may return a partial stack trace.
The Stack That You Were Looking For
The StackWalker API will allow laziness and frame filtering, it will support short walks that stop at a frame matching given criteria and will also offer support for long walks, that cross the entire stack. It will allow efficient lazy access to additional stack frames when required.
According to the official Oracle description of this Java Enhancement Proposal, the new feature is meant to define a capability-based StackWalker API to traverse the stack. Oracle also plans on enhancing the JVM to provide a flexible mechanism, to give the required stack-frame information and to allow the efficient lazy access to additional stack frames when required.
On the practical side, the API will specify its behavior when running with a security manager, so that access to the Class objects in stack frames do not compromise security.
If you want to try out the Stack-Walking API before Java 9 release date, you can do it right now through the “Microbenchmark of Java 9 StackWalker API” GitHub library. It’s composed of StackTraceBenchmark that measures how long it takes to retrieve the 5 last elements of a stack trace without actually using them.
The second file in this library is FileAndLineNumberBenchmark, that measures how long it takes to get the filename and line number of those elements.
It feels like Java 9 is just around the corner, and new, improved or redesigned features and abilities keep on popping up and catching our attention. We know that we can hardly wait for July 2017 and the official launch.
What are the features or JEPs you can’t wait to try out for yourselves? We would love to hear about them in the comments below.