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.
What Is a REPL (Read–Eval–Print Loop)?
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.
Why Use JShell?
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:
- Write a complete program.
- Compile it and fix any errors.
- Run the program.
- Figure out what is wrong with it.
- Edit it.
- Repeat the 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.
What is JShell Good For?
- Exploring a new API or language feature (Experiment and instantly see results)
- New to Java, new to programming (Start with expressions vs classes, immediate feedback)
- Prototyping (Write complex code incrementally)
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
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
" 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
audience strings into a new variable called
saying. Start by typing
var saying = gr
. 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:
Control Flow Statements (if-else, while loops, for loops)
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:
Defining and Invoking Methods
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:
Creating Classes and Objects
You’re not just limited to simple statements and functions. You can also create classes, interfaces and enums in JShell:
Exploring JShell Commands
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.
/? to get a list of all the available commands. Let’s look at some of these commands:
/imports – List all available imports
JShell imports some of the most used and important Java packages by default when you start a session.
/importsto get a list of all these imports.
You can import additional packages in a JShell session like this
/vars – List all the variables defined in the current JShell session
/varslists all the variables that are declared in the current JShell session along with their value:
/methods – List all the methods defined in the current JShell session
/edit – Edit an already defined method, variable or class
You can edit an already defined method or variable using the
/editcommand. In the following example, I’m editing the
sum()method that we have defined earlier.
/save – Save the current workspace to a file
You can save the whole source code that you have typed in the current JShell session in a file using the
/open – Open an already saved workspace
/opencommand 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
/opencommand to load a class in the JShell session from an external file.
Assuming you have defined a class named ExampleClass in the current working directory, here is how you can load the class in JShell:
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.