Java 9 - JShell
As I have been developing in Groovy for quite some time (and still enjoy it whenever I get a chance to use it), I always was quite a fan of using the Groovy Console for testing small code snippets and doing API experiments.
With Java 9, there finally comes a nearly equivalent command line tool (it’s command-line, not a Swing GUI) bundled with the JDK: jshell.
jshell command can be found alongside the
javac commands and the other usual suspects in the
bin directory of your JDK installation. On my mac, it can be found in
/Library/Java/JavaVirtualMachines/jdk-9.jdk/Contents/Home. Note the JDK 9 directory name does not contain the obligatory “1.” prefix we had for all the pevious Java versions (which was actually already announced for Java 5).
Once you find the
jshell command or if you’ve added the directory in your operating system’s environment path, you can simply run
jshell in the command-line.
JShell implements a so-called “read-eval-print” loop (REPL). Nowadays, a vast majority of modern programming languages come with REPLs. So it has only been a matter of time since Java gets an offical REPL.
A REPL basically provides a command-line/shell interface where certain expressions and statements can be specified in a particular programming language. Once you press
ENTER the current line gets read and evaluated and results are usually stored in REPL-local variables. It’s possible to explicitly define local variables too though.
In JShell, according to JEP 222, those code pieces are referred to as snippets. A snippet may be an expression, a statement, class/interface declaration, field/method implementation or and import declaration. Notice that a snippet might be a full class declaration, so truth be told it’s actually possible to have multiple lines of code belonging to a single snippet, snippets must not be one-liners.
The Java REPL
Let’s have a look at an example. With
jshell started, you can do stuff like that:
As you can see above,
jshell allows either explicit or implicit variable declarations. Implicitly generated variables have the prefix
X is the so-called snippet identifier.
Variables are not wrapped in a user-visible class, although internally synthetic code is generated. Variales can be seen as global inside the current
jshell session. Internally, variables, methods and classes declared in JShell are compiled to static members of a synthetic (generated) class. Expressions and statements are compiled to static methods, again in a synthetic class.
As for creating collections inside JShell, it’s convenient to know and use the new static factory methods in the JDK 9 collection classes, this is,
Of course another convenient features in this context is the Java 8 lamda syntax which allows use to declare code-blocks in a very compact syntax:
As you might have noticed, it’s unnecessary to execute an import statement for the referenced collection classes.
jshell imports a default package list. The imported packages can be shown with the
/imports command, being one of the special
/* commands (besides
/exit btw ;-)):
/help shows additional commands specific to the JShell command line tool.
There are commands for listing the created snippets, variables, methods, types etc. It’s even possible to modify the source of existing snippets used previously with
/edit X (X is the snipped identifier) and store those snippets in distinct files via
/store X <file>. Re-running snippets is done via
/X. I guess there is some more cool stuff to discover there.
Not only is JShell a command-line tool. It even comes with an API for integrating JShell into JVM-based applications.
jdk.shell comes with four packages whereas the first package is interesting for integration requirements:
jdk.shell: contains an API for programtically creating and evaluating snippets
jdk.shell.spi: contains service provider interfaces for custom execution engine implementations. The default implementation for
jshellis found in the
jdk.shell.executionpackage, being the third package
jdk.shell.tool: this package has the
JavaShellToolBuilderfor launching the shell programtically
Let’s have a brief look at the
The central class there is
JShell. It is the central container for snippets together with the execution state those snippets have produced. Every source code snippet is represented as an instance of Snippet at runtime.
SnippetEvent instances are fired once new snippets are added/removed or existing snippets have been updated. It gets particularly interesting when snippets belong to each other and one of the snippets gets dropped. JShell might end up with an unresolved reference to some entity (for example a variable), its the event listeners to task to react in such a scenario (or to end up with an unresolved reference in such a scenario).
Finally, starting with Java 9, JDK comes bundled with a Java REPL (read-eval-print loop) called
jshell. In this article we give a first overview of JShell and JShell API.