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

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!" jshell>

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

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() Foo Bar jshell>

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 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.* jshell> /m | foo ()void | bar ()void jshell>

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(String original) String(char[] value) String(char[] value, int offset, int count) … String(StringBuilder builder) <press shift-tab again to see javadoc> String() 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") jshell>

Conclusion

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

Originally published at www.polidea.com by Łukasz Gajowy

Show your support

Clapping shows how much you appreciated Polidea’s story.