Many compiled languages include tools (sometimes called REPL) for statements interpretation. Using these tools you can test code snippets rapidly without creating project.
Take Scala as an example. Compilation can sometimes take a long time, but using repl each statement is executed instantly! That’s great when you are getting started with the language. Each expression gives you returned value and it’s type - that’s very valuable information.
In java, instead, we have to create a test or main method which prints results and needs to be recompiled every time you make a change.
When?
JShell will be introduced in Java 9 realease. You can however get early access build on https://jdk9.java.net/.
Running
Once you downloaded jdk9 there is a jshell executable in a bin directory. I suggest running it in verbose (-v
) mode for the first time:
kuba@kuba-laptop:~/repos$ jdk-9/bin/jshell -v
| Welcome to JShell -- Version 9-ea
| For an introduction type: /help intro
jshell>
You can go back to non verbose mode using /set feedback normal
.
Default imports
By default you get a set of common imports:
jshell> /imports
| import java.util.*
| import java.io.*
| import java.math.*
| import java.net.*
| import java.util.concurrent.*
| import java.util.prefs.*
| import java.util.regex.*
You can add your own any time.
Expressions
You can type any valid java expression, and it will tell you the returned value, it’s type and assign it to a variable:
jshell> 3+3
$1 ==> 6
| created scratch variable $9 : int
jshell> $1
$1 ==> 6
| value of $1 : int
Variables
It is possible to declare variables and name them. Once you do that they become visible in the scope.
jshell> int x=5
x ==> 5
| created variable x : int
jshell> x
x ==> 5
| value of x : int
Methods
You can also define methods and even replace them:
jshell> void helloJShell() { System.out.println("hello JShell"); }
| created method helloJShell()
jshell> helloJShell();
hello JShell
jshell> void helloJShell() { System.out.println("wow, I replaced a method"); }
| modified method helloJShell()
| update overwrote method helloJShell()
jshell> helloJShell()
wow, I replaced a method
Commands
Aparat from language syntax you can execute jshell commands. Some of the most useful ones (/help
to list all of them) are:
listing variables
jshell> /vars
| int x = 0
| double j = 0.5
listing methods:
jshell> /methods
| printf (String,Object...)void
| helloJShell ()void
The printf method is defined by default.
listing sources
jshell> /list
14 : helloJShell();
15 : void helloJShell() { System.out.println("wow, I replaced a method"); }
16 : helloJShell()
editing sources in external editor
jshell> /edit helloJShell
Opens external editor, and replaces helloJShell method.
Example use cases
After 20 years of Java without REPL one might wonder what scenarios are suitable for JShell. Here are some examples.
Veryfing return type
Remember the time you learned that dividing two integers in Java does not result in floating number? For some time I was convinced that both numerator and denominator have to be floating for a result to be floating too. Let’s test that:
jshell> 1/2
$1 ==> 0
| created scratch variable $1 : int
jshell> 1.0/2
$2 ==> 0.5
| created scratch variable $2 : double
jshell> 1/2.0
$3 ==> 0.5
| created scratch variable $3 : double
jshell> 1.0f/2
$4 ==> 0.5
| created scratch variable $4 : float
jshell> 1/2.0f
$5 ==> 0.5
| created scratch variable $5 : float
Turns out only one of them has to be floating.
Testing Java niuanses
Did you know that comparing autoboxed integers references which values are from range -128 to 127 (inclusive) returns true (they are cached)? You can verify that with shell in a matter of seconds:
jshell> Integer i1 = 127
i1 ==> 127
jshell> Integer i2 = 127
i2 ==> 127
jshell> i1 == i2
$35 ==> true
jshell> Integer i2 = 128
i2 ==> 128
jshell> Integer i1 = 128
i1 ==> 128
jshell> i1 == i2
$38 ==> false
Formatting
Sometimes the logs need to be verbose and properly formatted. This is tedious task and usually leads to few recompile cycles which significantly slows us down. Imagine you forgot what was the format sign responsible for integers. You can quickly verify that:
Let’s try %i
(integer):
jshell> printf("I got %i apple",1)
| java.util.UnknownFormatConversionException thrown: Conversion = 'i'
| at Formatter$FormatSpecifier.conversion (Formatter.java:2691)
| at Formatter$FormatSpecifier.<init> (Formatter.java:2717)
| at Formatter.parse (Formatter.java:2565)
| at Formatter.format (Formatter.java:2507)
| at PrintStream.format (PrintStream.java:977)
| at PrintStream.printf (PrintStream.java:873)
| at printf (#s8:1)
| at (#51:1)
Oops, maybe %d
(decimal) :
jshell> printf("I got %d apple",1)
I got 1 apple
Conclusion
JShell is a very useful tool for prototyping and testing Java code snippets. Even though it is not yet officially released I highly recommend checking it out. There is also a JShell Java api which allows you to evaluate JShell from java. Once the java 9 is out I bet there will be JShell integrations in most popualar IDEs - this will make using it even more handy.
- jshell (1) ,
- java 9 (1) ,
- 9 (1) ,
- java (24) ,
- api (1) ,
- repl (1) ,
- interpreter (1) ,
- getting (1) ,
- started (1) ,
- examples (1)