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