Introduction to the first official Java REPL - JShell

JShell is Java’s first official REPL (READ-EVAL-PRINT-LOOP) tool. It is part of JDK 9 which is released recently by Oracle.

JShell REPL creates a simple programming environment in the command line that reads user’s input, evaluates it, prints the result, and then repeats the same cycle.

It works similar to Python interpreter or other JVM languages that have a REPL like Scala, Kotlin and Groovy.

You can write Java language expressions and statements in the JShell REPL, and they will be evaluated on their own without having to wrap them in classes or methods.

In this article, You’ll first setup JShell in your machine and then learn to play around with it using simple examples.

Hello JShell

JShell comes bundled with JDK 9. You can download JDK 9 from Oracle’s Java SE Downloads Page. Before proceeding further, download JDK 9 for your operating system and set it up in your PATH variable.

Once JDK 9 is installed, type jshell in your terminal to start a JShell session -

$ jshell
|  Welcome to JShell -- Version 9
|  For an introduction type: /help intro

jshell> 

An interactive JShell session will be started and JShell will greet you with a welcome message.

If this doesn’t work, Please make sure that JAVA_HOME is set in your machine and JAVA_HOME/bin is added to the PATH variable. All the JDK tools including Jshell are located inside JAVA_HOME/bin directory.

If it worked, then let’s write our first Hello, World example using JShell -

jshell> System.out.println("Hello, World!")
Hello, World!

Yeah! That’s all you need to do! No need to define a class, create a main method and print hello world inside the main method. Just type the print statement, press enter and walla, you get the result instantly!

Also, You might have noticed that I didn’t terminate the statement with a Semicolon. Yes, Semicolons are Optional for bare expressions and statements. However, they’re required when you write multi-line statements or methods.

Variables and Expressions

You can type any valid Java expression in the REPL, be it arithmetic operation, string manipulation, method call, whatever, and it will be evaluated immediately.

jshell> 2+2
$1 ==> 4

jshell> 12*8
$2 ==> 96

As you might have noticed, all the results are automatically assigned to a variable created by the REPL. These variables are prefixed with $. You can refer them in the REPL like this -

jshell> $1 + $2
$3 ==> 100

You can also create your own variables and refer them like this -

jshell> int width = 40
width ==> 40

jshell> int height = 30
height ==> 30

jshell> int area = width * height
area ==> 1200

Following are some examples of String manipulation in the REPL -

jshell> "Hello, " + "World"
$7 ==> "Hello, World"
jshell> String greeting = "Hello, World"
greeting ==> "Hello, World"

jshell> greeting.toUpperCase()
$9 ==> "HELLO, WORLD"

jshell> greeting.substring(0, 5)
$10 ==> "Hello"

jshell> greeting.split(",")
$11 ==> String[2] { "Hello", " World" }

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.

Following is an example of If-Else statement -

jshell> int age = 25
age ==> 25

jshell> if(age < 25) {
   ...>     System.out.println("Child!");
   ...> } else {
   ...>     System.out.println("Adult!");
   ...> }
Adult!

And, Here is how you can use a while loop in the REPL -

jshell> int i = 0
i ==> 0

jshell> while(i < 10) {
   ...>     System.out.print(i + " ");
   ...>     i++;
   ...> }
0 1 2 3 4 5 6 7 8 9

Finally, following is an example of a For-Loop -

jshell> String[] animals = {"Cat", "Dog", "Lion", "Tiger"}
animals ==> String[4] { "Cat", "Dog", "Lion", "Tiger" }

jshell> for(String animal : animals) {
   ...>     System.out.println(animal);
   ...> }
Cat
Dog
Lion
Tiger

Defining and Invoking Methods

You can define methods in the REPL similar to how you define them in Java classes -

jshell> int sum(int a, int b) {
   ...>     return a + b;
   ...> }
|  created method sum(int,int)

Once a method is created in a JShell session, you can call it anytime until you quit that session -

jshell> sum(4, 5)
$12 ==> 9

Creating Classes and Objects

You’re not just limited to simple statements and functions. You can also create classes, interfaces and enums in JShell -

jshell> class Circle {
   ...>     private double radius;
   ...>     Circle(double radius) {
   ...>         this.radius = radius;
   ...>     }
   ...>     double getRadius() {
   ...>         return radius;
   ...>     }
   ...>     void setRadius(double radius) {
   ...>         this.radius = radius;
   ...>     }
   ...>     double calculateArea() {
   ...>         return 2 * Math.PI * radius;
   ...>     }
   ...> }
|  created class Circle
jshell> Circle c = new Circle(5.0)
c ==> Circle@1ce92674

jshell> c.calculateArea()
$3 ==> 31.41592653589793

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 workspace.

Type /help or /? to get a list of all the available commands. Let’s look at some of these commands -

1. /imports - List all available imports

JShell imports some of the most used and important Java packages by default when you start a session. Type /imports command to get a list of all these imports -

jshell> /imports
|    import java.io.*
|    import java.math.*
|    import java.net.*
|    import java.nio.file.*
|    import java.util.*
|    import java.util.concurrent.*
|    import java.util.function.*
|    import java.util.prefs.*
|    import java.util.regex.*
|    import java.util.stream.*

You can import additional packages in JShell session like this -

jshell> import java.time.*

Once you do this, /imports command will start showing the new import as well.

2. /vars - List all the variables defined in the current JShell session

/vars command lists all the variables that are declared in the current JShell session along with their value -

jshell> /vars
|    int $1 = 4
|    int $2 = 96
|    int $3 = 100
|    int width = 40
|    int height = 30
|    int area = 1200
|    String $7 = "Hello, World"
|    String greeting = "Hello, World"
|    String $9 = "HELLO, WORLD"
|    String $10 = "Hello"
|    String[] $11 = String[2] { "Hello", " World" }
|    int age = 25
|    int i = 10
|    String[] animals = String[4] { "Cat", "Dog", "Lion", "Tiger" }
|    int $17 = 9

3. /methods - List all the methods defined in the current JShell session

jshell> /methods
|    int sum(int,int)

4. /types - List all the classes, interfaces and enums defined in the current JShell session

jshell> /types
|    class Circle

5. /edit - Edit an already defined method, variable or class

You can edit an already defined method or variable using /edit command. In the following example, I’m editing the sum() method that we defined earlier.

jshell> /edit sum

The /edit command opens an editor where you can edit the method and then save it. When you exit the editor, JShell will tell you that the method is modified -

|  modified method sum(int,int)

6. /set - Set JShell configuration info

The /set command allows you to configure JShell environment.

If you used the /edit command in the previous section, then you might have noticed that JShell opens the source in its default editor. If let’s say, you want to use Vim instead of the default editor, you can set it using the following command -

jshell> /set editor vim
|  Editor set to: vim

7. /save - Save the current workspace to a file

You can save all the source that you have typed in the current JShell session in a file using /save command -

jshell> /save experiments.txt

8. /open - Open an already saved workspace

The /open command allows you to open a file as source input for the current JShell session -

jshell> /open experiments.txt

Apart from loading snippets and commands from external files, you can also use /open command to load a class in the JShell session from an external file.

Assuming you have defined a class named Square in the current working directory, Here is how you can load the class in JShell -

jshell> /open Square.java

If you check the output of /types command, the new class will be listed in the output -

jshell> /types
|    class Circle
|    class Square

Other Useful Features

1. Tab Completion

You get tab completion out of the box with JShell. You can type part of the source and press tab for suggestions. Consider the following example -

jshell> URL blogUrl = new URL("https://www.callicoder.com")
blogUrl ==> https://www.callicoder.com

Now, for checking what methods are available for use for the above URL object, type blogUrl followed by a dot (.), and then press tab -

jshell> blogUrl.
equals(            getAuthority()     getClass()         getContent(        getDefaultPort()   getFile()          getHost()          getPath()          
getPort()          getProtocol()      getQuery()         getRef()           getUserInfo()      hashCode()         notify()           notifyAll()        
openConnection(    openStream()       sameFile(          toExternalForm()   toString()         toURI()            wait(              

jshell> blogUrl.

JShell will display all the methods that you can use on the blogUrl object. This is awesome! isn’t it? :)

2. Forward References

JShell supports forward references. That means you can define functions that refer to other methods or variables that will be defined later -

jshell> int geometricSequence(int a, int r, int n) {
   ...>     return a * pow(r, n-1);
   ...> }
|  created method geometricSequence(int,int,int), however, it cannot be invoked until method pow(int,int) is declared

3. Redeclaring Variables and Methods

You can re-declare variables and methods without worrying about any previous declarations.

In the following example, the variable foo is simply re-declared every time -

jshell> int foo = 123
foo ==> 123

jshell> int foo = 567
foo ==> 567

jshell> String foo = "Hello"
foo ==> "Hello"

Similarly, you can change the definition of methods as well -

jshell> int multiply(int a, int b) {
   ...>     return a * b;
   ...> }
|  created method multiply(int,int)

jshell> int multiply(int a, int b) {
   ...>     // Multiplying two numbers
   ...>     return a * b;
   ...> }
|  modified method multiply(int,int)

JShell will simply say that It has modified an already existing method with the same name.

4. No checked Exceptions

Checked exceptions are automatically wrapped by JShell in the background. So you don’t have to catch them explicitly -

jshell> Thread.sleep(1000)

However, If you’re writing an entire method instead of a single statement, then you’ll need to handle checked exceptions -

jshell> Thread myThread = new Thread(() -> {
   ...>     Thread.sleep(1000);
   ...> });
|  Error:
|  unreported exception java.lang.InterruptedException; must be caught or declared to be thrown
|      Thread.sleep(1000);
|      ^----------------^

Additional Examples

Collections

jshell> List<String> animals = List.of("Cat", "Dog", "Elephant", "Lion", "Tiger")
animals ==> [Cat, Dog, Elephant, Lion, Tiger]

jshell> animals.forEach(animal -> System.out.print(animal + " "))
Cat Dog Elephant Lion Tiger


jshell> Map<String, Integer> myMap = Map.of("one", 1, "two", 2, "three", 3)
myMap ==> {two=2, three=3, one=1}


jshell> Set<Integer> mySet = Set.of(1, 2, 4, 8, 16, 32)
mySet ==> [32, 4, 8, 2, 1, 16]

Streams

jshell> Stream<Integer> myStream = Stream.of(1, 2, 3, 4, 5)
myStream ==> java.util.stream.ReferencePipeline$Head@e720b71

jshell> myStream.map(number -> number * number).
   ...> filter(number -> number % 2 == 0).
   ...> forEach(System.out::println)
4
16

DateTime

jshell> import java.time.*;

jshell> LocalDateTime.now()
$30 ==> 2017-08-29T09:15:15.603432

Conclusion

JShell is definitely one of the coolest features of Java 9. It will help beginners get a grasp of the language quickly. Moreover, It will help other developers run quick experiments without writing classes, methods, imports and all that boilerplate.

I urge you to try out JShell and let me know your views about it in the comment section below.

Thank you for reading folks. See you in the next post. Happy Coding!