February 23, 2017   |   5min read

Exploring Java 9: The JShell

Java 9 had its delays but it’s finally coming (there is even a counter showing when)! It’s going to bring us some cool stuff that has never been there, namely: Modules, HTTP 2.0 support, improvements in Processing API, G1 Garbage Collector as the default one… We could go on and on, because there are lots of JEPs included (the full list is available here) so let’s just focus on one neat and helpful tool that Java 9 release will bring us - the JShell.

A language shell

Let’s say you are prototyping. Or you want to learn something. Or teach someone. You probably want to know (see) what exactly happens after each line of an entered code. You don’t want to focus on setting up the project, creating .java file, writing your main class and the main method, compiling, running… it’s cumbersome and I already feel discouraged!

For such cases we need something that gives us quick feedback, leaving unimportant stuff behind. And that’s what REPLs are for. They:

  • Read the code you enter,
  • Evaluate it,
  • Print the result,
  • Do it on and on until you tell them to stop (L stands for Loop).

Java creators decided to introduce a REPL in the ninth version. It’s called JShell and I’ll try to show you how easy this tool is and what power it has.

The JShell:

JShell, aka project Kulla, comes with JDK9 - you don’t need to install anything else. Run it by typing “jshell” in the console. It will greet you with nice, welcoming message:

lukasz@MacBook ~> jshell
| Welcome to JShell -- Version 9-ea
| For an introduction type: /help intro

Nothing can stop me from writing a code snippet now:

jshell> "Hello "
$1 ==> "Hello "
jshell> $1.
charAt( chars() codePointAt(
codePointBefore( codePointCount( codePoints()
compareTo( compareToIgnoreCase( concat(
contains( contentEquals( endsWith(
equals( equalsIgnoreCase( getBytes(
getChars( getClass() hashCode()
indexOf( intern() isEmpty()
lastIndexOf( length() matches(
notify() notifyAll() offsetByCodePoints(
regionMatches( replace( replaceAll(
replaceFirst( split( startsWith(
subSequence( substring( toCharArray()
toLowerCase( toString() toUpperCase(
trim() wait(

jshell> $1.concat("there!")
$2 ==> "Hello there!"


Three things to notice here. First, JShell puts the result of the evaluated code into variables so that I could use it later. Second, I somehow made it to show us all possible methods I can invoke on the variables type (it was the Tab button, no surprise here). Third - there was no semicolon. This has been taken away from us in JShell to make our work more convenient.

Actually, there is one more thing that we do not have to worry about while coding in JShell. The checked exceptions:

//no “try” here
jshell> Thread.sleep(1000)
// (no “catch (InterrupedException ex”) here either


Another useful thing we can do in JShell is using yet undeclared code:

jshell> void foo() {
...> System.out.println("Foo");
...> bar();
...> }
| created method foo(), however, it cannot be invoked until method bar() is declared

jshell> void bar() {
...> System.out.println("Bar");
...> }
| created method bar()

jshell> foo()


As you can see, JShell has agreed to using the bar() method. It displayed a message informing that I should declare the method before invoking code that uses it. Also - an important thing to notice: here I had to put semicolons in methods (the same goes with try/catch blocks for checked exceptions). In fact, this seems to be a good thing in methods.\ It’s nice that I can just copy and paste them from JShell to the program I’m working on, isn’t it?

So far, so good, but we probably might want to check, what is going on with my JShell session. There are appropriate commands to do that too (/vars, /methods, /types, /imports):

jshell> /vars
| String $1 = "Hello"
|    String $2 = "Hello there!"

jshell> /methods
| foo ()void
| bar ()void

jshell> /types
| interface Baz
| class BazImpl

jshell> /imports
| import
| import java.math._
| import
| import java.nio.file._
| import java.util._
| import java.util.concurrent._
| import java.util.function._
| import java.util.prefs._
| import java.util.regex._
| import

jshell> /m
| foo ()void
| bar ()void


Yet another coding booster: if there is no ambiguity, we don’t have to write the whole command name.

What if we would like to edit something? On top redefining variables, methods and types, dropping them (/drop) and writing again, there is yet another interesting tool. The /edit command. By using it, we can write whatever code we like in a simple text editor and hit accept. This can become very handy while putting a long text to a variable, like this:


Last but not least - there are shortcuts. I already mentioned the “Tab” completion but JShell creators didn’t stop there. “Shift + Tab” allows us to see what constructors or methods are there to use. Pressing it twice opens the Javadoc.

jshell> new String( //press the combination here
String(String original)
String(char[] value)
String(char[] value, int offset, int count)
String(StringBuilder builder)
<press shift-tab again to see javadoc>

Initializes a newly created String object so that it represents an empty character
sequence.Note that use of this constructor is unnecessary since Strings are immutable.
<press space for next javadoc, Q to quit>

JShell can also infer types while declaring things. Simply press ”fn + esc + v” (shortcut for Mac OS - may differ on other platforms) at the end of a variable you’re creating. JShell will automatically tell you what the type is. Now all you need to do is to name the variable:

jshell> new String("Infer my type") //press the combination here
jshell> String <put the name here> = new String("Infer my type")


We need fine and intuitive tools and JShell is certainly one of them. It’s easy to learn, has a lot of handy features and it’s not too big. If you’re still curious, simply enter the /help command and check it out yourself! For me it was a pleasure and that makes it yet another good reason to look forward to Java9. Stay tuned for more!

jshell> /exit
| Goodbye
lukasz@MacBook ~>

Łukasz Gajowy

Senior Software Engineer

Did you enjoy the read?

If you have any questions, don’t hesitate to ask!