JShell, the Java REPL
Many languages contain a REPL, a Read-Evaluate-Print Loop. It evaluates declarations, statements, and expressions as they are entered and immediately shows the results. With Java 9, we finally got one too.
Quickly running some code without starting a full-blown IDE, or creating a scratch project can be immensely helpful. It can be used for prototyping code, trying some new functionality, or running a small part of a bigger project.
Table of Contents
Lines starting with
# are added for explanation purposes and are not part of the JShell output.
To start a new JShell session, just type
jshell in your favorite terminal / command line:
JShell evaluates everything you throw at it: expressions, statements, imports, or definitions. These chunks of Java code are called “snippets”.
No semicolons are needed for single-line snippets. If we define a method or class, we still need semicolons for the contents of curly brackets.
Any value returned by a snippet is automatically saved into a “scratch variable”, named
$<number>. Now the result of the expression is available to use later on.
To list all variables of the active session, type
/vars, which will print all scratch and non-scratch variables:
By default, only a small subset of the JDK is imported automatically.
/imports lists all imported packages and classes of the current JShell session:
We can import other packages and classes just like we would in “normal” Java code:
Or we can instruct JShell to load a different set of packages on start-up by using a predefined load-file:
This will load ~170 different packages from the JDK, instead of just the bare minimum.
No one wants to type out all the imports needed for working with Java code. It’s a good thing JShell has you covered!
To import a type we can press
shift-tab i at the end of any type, and JShell tries to find the correct type based on the context:
Not always an import-candidate will be found. But most of the time, it will make using JShell easier.
Expressions to Variables
Another handy shortcut is
shift-tab v which will convert an expression to a variable creation statement:
The variable type will be inferred and inserted automatically, just give it a name, press
enter, and you converted your expression to a named variable.
The Power of Tab
The tab completion is really powerful and can be used to complete snippets and commands. Pressing
tab multiple times increases the amount of information provided.
If we found the correct method, we can see all available signatures by pressing
tab again after the parenthesis:
As indicated in the output, pressing
tab again (and again and again) will cycle through the documentation of every signature.
Methods & Classes
Methods and classes can be declared “as usual”:
Thanks to forward referencing, our methods and classes can use variables and other constructs that aren’t even declared yet. JShell warns us about it, though:
This allows us to set up our environment easier than ensuring everything has to be in place before creating methods etc.
Java control flow statements are supported:
? :Ternary operator
There are multiple ways to work with previous snippets.
/history will display all snippets and commands of the currently active session in plain text.
/list instead, we get a list of snippets, but not commands, and their corresponding ID.
The ID can be used in other commands.
JShell supports backward and forward searching:
We already learned about some available commands, like
Many commands have different options. We can check them out by typing
/help for a short overview. For a detailed explanation of a command, use
/? <command> or
List of Commands
We don’t have to type out the full command, just enough to make it unique:
/s wouldn’t be enough for
/set, thanks to
Java provides a lot of functionality, but being able to use any JAR file in JShell makes it a potent tool for prototyping.
We can either specify the classpath on startup:
Or we can set it during an active session:
Beware, the session will be reset, and everything not in a start-up script will be gone.
Java 9 Modules
Module usage are similar to using classpaths:
This can also be set in an active session:
With the help of
/set, we can configure JShell to our liking.
Like other commands,
editor has additional options, you can check them out with
/help /set editor.
By default, all
/set commands are only set for the duration of the current session. To set a configuration option permanently, we need to add the argument
-retain at the end.
But be aware, not every retained option can be removed with
-delete like the editor option.
I’ve tried to find out where JShell saves its configuration, but couldn’t find it, even after checking out the source code.
We can configure the output provided by JShell in quite detail. But this would make this article twice or thrice as long.
If you’re interested in configuring the output, you should check out the
/set mode and
/set format options.
JShell Feedback Mode Documentation (Oracle)
Working with Scripts
As mentioned before, JShell loads a default start-up script to prepare the session with useful imports.
We can use our own script at startup to prepare it the way we like it:
To use more than one start-up script, we need to use the argument
Or we can use
/set start -retain [scripts] instead.
There are 3 built-in start-up scripts available:
DEFAULT: Loads a minimum of imports, used if no load-file is specified.
JAVASE: Loads ~175 different JDK packages.
PRINTING: Loads the same imports as
DEFAULT, but also adds multiple
Startup scripts are always run when the session resets:
- Initial start-up
Loading a script into a session is also possible:
/open [load-file] in a session.
Unlike a start-up script, it won’t be reloaded when the session resets.