JShell

For those who haven’t heard the news, Java has officially its own shell, named (obviously) JShell since Java 9. It is a REPL type of environment where you type your code in the command line interface and see the results immediately on your screen. This is a good way to test simple programming concepts and ideas without the inherited boilerplate verbosity, which JUnit or main function has. Also semicolons in the end are optional!

Before we dive into the commands lets take a look under the hood and see how it works. Whenever we execute a piece of code (snippet), we first interact with the command line interface. JShell implementation is build on top of 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. Responsible for sending the bytecode to the JVM is the Java Debug Interface. The thought process behind this architectural approach is that if the JVM crashes, your application is not affected. After the code is executed, the result is sent back to the command line interface through a socket.

jshell architecture

To enter the JShell environment, just type >jshell on the command line. There are two preferred ways to launch JShell on your console, the first is by typing >jshell and the second is >jshell -v which enables the verbosity mode. You can see their difference in the example below:

//without verbosity option
furiousprogrammer@FuriousPC:~$ jshell
|  Welcome to JShell -- Version 10.0.2
|  For an introduction type: /help intro

jshell> 1+1
$1 ==> 2

//with verbosity
furiousprogrammer@FuriousPC:~$ jshell -v
|  Welcome to JShell -- Version 10.0.2
|  For an introduction type: /help intro

jshell> 1+1
$1 ==> 2
|  created scratch variable $1 : int

So, in simple terms, -v option, gives you more info about what is going on with your commands. If you want to switch back to simple mode type: /set feedback normal

With JShell you can write any kind of Java command you like. Just as you normally do with your programs, you can type methods, classes, imports variables etc..

jshell> System.out.println("Hey there fellow programmer!")
Hey there fellow programmer!

jshell> System.out.println($1);
2

jshell> public class furiousClass{}
|  created class furiousClass

jshell> public interface  furiousInterface{}
|  created interface furiousInterface

jshell> int furiousInteger = 1
furiousInteger ==> 1
|  created variable furiousInteger : int

jshell> String furiousString = "Hi there!"
furiousString ==> "Hi there!"
|  created variable furiousString : String

jshell> 13/53
$10 ==> 0
|  created scratch variable $10 : int

jshell> $10 = 75
$10 ==> 75
|  assigned to $10 : int

jshell> String furiousMethod(String arg){ throw new RuntimeException("Lets brake some staff");}
|  created method furiousMethod(String)

jshell> furiousMethod("Hi!")
|  java.lang.RuntimeException thrown: Lets brake some staff
|        at furiousMethod (#13:1)
|        at (#14:1)


JShell and Forward References

JShell gives you the ability to declare methods, whose bodies reference methods, variables, or classes which are not yet defined. But by the time you decide to invoke them though, you ought to have them defined.

jshell> public void printBlogName(){ System.out.println("My blog name is: "+ blogName);}
|  created method printBlogName(), however, it cannot be invoked until variable blogName is declared

If you decide to YOLO and ignore the JShell warning you will get this:

jshell> printBlogName()
|  attempted to call method printBlogName() which cannot be invoked until variable blogName is declared

After the variable declaration this is the result:

jshell> String blogName="TheFuriousProgrammer"
blogName ==> "TheFuriousProgrammer"
|  created variable blogName : String
|    update modified method printBlogName()

jshell> printBlogName()
My blog name is: TheFuriousProgrammer


Basic Commands

Here are some basic commands to help get started!

/vars lists all variables used during your session and their values. As you might have noticed all variables who are generated by JShell start with $.

jshell> /vars
|    int $1 = 2
|    int furiousInteger = 1
|    String furiousString = "Hi there!"

/types To see all declared classes and interfaces.

jshell> /types
|    class furiousClass
|    interface furiousInterface

/methods Lists all your methods and their signatures

jshell> /methods
|    String furiousMethod(String)

/list List the currently active snippets of code that you typed during your session.

/imports With the imports command, JShell will list the default imported packages.

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

If you need additional imports for your snippets, just type them in the console.

 jshell> import your.package.name.*

/help Will give you all available options and commands for JShell.

/save You can save your session experiments with this command on a file. The default file format extension for JShell is jsh but you can use other extensions as well.

//both are valid commands
/save output.txt

/save output.jsh
//the latter is best suited if you want to restore your session on JShell

/open Commands and declarations which where stored with a .jsh file extension, can be restored in your session by typing:

jshell> /open mytest.jsh

/debug Display debugging information for the JShell tool implementation.

After you enable debug mode and type something like a simple addition the following will print:

jshell> /debug
|  Debugging on

jshell> 1+1
Compiling: 1+1
Kind: EXPRESSION_STATEMENT -- 1 + 1;
compileAndLoad  [Unit($1)]
++setCompilationInfo() Snippet:VariableKey($1)#11-1+1
package REPL;
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.*;class $JShell$11 {
    public static
    int $1;
    public static Object do_it$() throws Throwable {
        return $1 =
        1+1;
    }
}

-- diags: []
setStatus() Snippet:VariableKey($1)#11-1+1 - status: VALID
compileAndLoad ins = [Unit($1)] -- legit = [Unit($1)]
Compiler generating class REPL.$JShell$11
compileAndLoad [Unit($1)] -- deps: []  success: true
recordCompilation: Snippet:VariableKey($1)#11-1+1 -- status VALID, unresolved []
$1 ==> 2
|  created scratch variable $1 : int

If you noticed, all imports are done automatically and they are the same packages we discussed on /imports command. Then the created variable is of type static. This is done so other snippets can access it in the future.

If you want to exit debug mode, type /debug 0 in the console


Useful tricks

1) for the commands above you can either type their full name or just type their abbreviation as long as it is unique ex: jshell> /sa out.jsh. If its not unique, you will get something like the following :

|  Command: '/e' is ambiguous: /edit, /exit, /env
|  Type /help for help.

2) when pressing tab you will receive a list of all available options for completing your command.

3) press ctrl+l to clear the terminal.


Additional resources

If you want to find an extended description of JShell, the best resource I have come across thus far is Oracle’s user guide and reference with multiple examples and cases for you to examine. Also a really great presentation I suggest you to watch is that of Robert Field who is one of the creators of JShell.