The shell or the REPL (read-eval-print-loop) is a well-known tool in many programming languages. Typically, this is more common in scripting languages such as Python or Node, but more recently it’s been adopted by JVM languages like Clojure and Groovy as well. The upcoming Java 9 release finally brings this shell functionality to the Java language as well, in the form of JShell. This blog post is a preview of the use of the new feature java 9 Jshell. More details about it you can find at web sites that are used as a source: Introduction Jshell and Tutorial Jshell.
Simply put, the REPL is an interactive shell into which we can enter commands and have these immediately executed and the results displayed.
The use of this tool can greatly help when trying out new ideas and techniques and when quickly testing code without having to write an entire test class to run.
At its core, this is all about an immediate feedback loop, so it can have a significant impact on productivity in that particular language.
When using JShell, you can enter your program elements one at a time, immediately see the result, and make adjustments as needed.
Java program development typically involves the following process:
JShell helps you try out code and easily explore options as you develop your program. You can test individual statements, try out different variations of a method, and experiment with unfamiliar APIs within your JShell session. JShell doesn’t replace an IDE. As you develop your program, paste code into JShell to try it out, and then copy and paste the working code from JShell into your program editor or IDE.
Before we dive into the commands, let’s look under the hood and see how it works. Whenever we execute a piece of code (a snippet), we first interact with the command line interface. The JShell implementation is built on top of the javac compiler and interacts with the command line through the JShell API. The execution of the generated bytecode is done to a remote JVM instance. The Java Debug Interface is responsible for sending the bytecode to the JVM. The thought process behind this architectural approach is that if the JVM crashes, your application will not be affected. After the code is executed, the result is sent back to the command line interface through a socket.
We'll be using Java 11 in this blog in order to take advantage of the var
keyword, so make sure you have at least Java 11 installed to follow along throughout this blog tour.
JShell is easily started by typing jshell
into the command line. You'll be presented with a welcome message and shell waiting for you to input commands or any valid Java expression.
Let's execute our first command. At the shell prompt, type var greeting = “hello”
and press . You should see get an output like this:
You'll notice that it echoes the value of the greeting, confirming that the value is now equal to hello
. You may also have noticed that you didn't need to end the expression with a semicolon. A small but nice feature!
In order to complete our greeting, we need an audience. Type var
audience
= “Serengeti” and press . This time, JShell recognizes that you're not finished with your expression and allows you to continue on the next line. Finish your expression by typing "Serengeti"
followed by . Just like before, JShell echoes the value confirming that it has been set.
One of the first things you'll notice is the nicely integrated tab completion. Let's concatenate our greeting
and audience
strings into a new variable called saying
. Start by typing var saying = gr
and then press . You'll see that the greeting variable is automatically completed. Do the same with the audience variable and press enter to see the result of the concatenation.
Tab completion works just as you'd expect, automatically completing values that are unique or providing potential values when it's ambiguous. It works on any previously typed expressions, objects, and methods. Note that it does not work on built-in keywords.
If you wanted to make the saying
variable all uppercase but you couldn't remember the exact name of the method, you could simply type saying.to
and then press tab to see all the valid possible methods that start with to, as so:
You can also write multi-line control flow statements in the REPL. JShell is smart enough to recognize multi-line statements and prompts with a…> symbol to let you enter the next line of the statement. The following is an example of an If-Else statement:
And, here is how you can use the while loop in the REPL:
Finally, the following is an example of a for-loop:
You can define methods in the REPL similar to how you define them in Java classes:
Once a method is created in a JShell session, you can call it anytime until you quit that session:
You’re not just limited to simple statements and functions. You can also create classes, interfaces and enums in JShell:
Apart from running Java language expressions and statements, JShell also provides some meta-commands to help you play around with the REPL environment.
You can use these commands to list the variables, methods, and imports available in the current JShell session, view the history of what you have typed, edit an already defined variable or method, save your workspace and open any existing workspaces.
Type /help
or /?
to get a list of all the available commands. Let’s look at some of these commands:
/imports
to get a list of all these imports./vars
lists all the variables that are declared in the current JShell session along with their value:
You can edit an already defined method or variable using the /edit
command. In the following example, I’m editing the sum()
method that we have defined earlier.
You can save the whole source code that you have typed in the current JShell session in a file using the /save
command
The /open
command allows you to open a file as the source input for the current JShell session
Apart from loading snippets and commands from external files, you can also use the /open
command to load a class in the JShell session from an external file.
Anytime we run a command in JShell that ends up in an Exception reaching the top of the stack, this is automatically handled by displaying the stack trace, including all line numbers, similar to how Java typically handles exceptions.
This can be quite helpful for easily diagnosing problems:
This tells us an exception was thrown on line 3 of the test() method, which itself was command 1 of the script. Therefore, we can immediately see what the offending statement was. Unfortunately, the lack of line numbers means that this is easiest when we have short functions to work with, which is, of course, good practice anyway.
JShell is definitely one of the coolest features of Java 9. It helps beginners get a grasp of the language quickly. Moreover, it helps other developers run quick experiments without writing classes, methods, imports and all that boilerplate.
Most modern languages and tools can be interacted with via a shell. Finally, starting with Java 9, so can the Java language itself – a feature that was missing for many years.
JShell is a fantastic tool that has a wide variety of uses. Naturally, the tool is most useful for quickly testing out some code to see how it works without needing to write an entire class, compile it and run it first.
This can greatly improve productivity when developing our code, and shorten the feedback cycle on testing things out.