JShell
jshell
is a new-in-Java-9 tool - a REPL for Java!! I was not sure at first how useful it would
be but since I started playing with it I’ve been finding more and more uses for it, and it’s pretty cool.
There’s a couple of surprising things though.
A quick look
$ jshell
| Welcome to JShell -- Version 9
| For an introduction type: /help intro
jshell>
and we’re at the REPL prompt. We can do a few totally unsurprising (but neat!) things:
jshell> 1+2
$1 ==> 3
jshell> "Hello".toUpperCase()
$2 ==> "HELLO"
There’s also a few meta commands, try starting with /help
The $n
are references to the results:
jshell> $2.getClass()
$3 ==> class java.lang.String
jshell> $3.getClass()
$4 ==> class java.lang.Class
etc. We can create, modify and replace classes on the fly:
jshell> class Apple{ int banana(){ return 0; } } // NB comments are OK
| created class Apple
jshell> class Apple{ int banana(){ return 100; } }
| modified class Apple
jshell> class Apple{ int banana(){ return 100; } int bigBanana(){ return 1_000_000; } }
| replaced class Apple
Classes are created
then modified
or replaced
when changed. If the change alters a method signature or adds/removes a field then the class is replaced
, otherwise it is just modified
. What happens to instances when you do that?
Modifying a class
Modifying a class alters existing instances:
jshell> class Apple{ int banana(){ return 100; } }
| created class Apple
jshell> Apple a = new Apple()
a ==> Apple@18eed359
jshell> a.banana()
$41 ==> 100
jshell> class Apple{ int banana(){ return 101; } } // <-- modification
| modified class Apple
jshell> a.banana()
$43 ==> 101
Replacing a class
Replacing a class nullifies instance references:
jshell> class Apple{ int banana(){ return 101; } int bigBanana(){return 10000000;} }
| replaced class Apple
| update replaced variable a, reset to null
jshell> a // it's not lying!
a ==> null
Semicolon insertion
My inner Douglas-Crockford is bristling at this a bit, to be honest. Semi-colons are optional. You might notice I haven’t used any in the code above. The rule seems to be that if an expression can be evaluated, then it will be. So be careful typing code like:
"Hello".toUpperCase()
.indexOf("O");
Because you’ll get this:
jshell> "Hello".toUpperCase()
$47 ==> "HELLO"
jshell> .indexOf("O");
| Error:
| illegal start of expression
| .indexOf("O");
|
I use three ways to cope with this:
- Everything on one line. Not nice with long lines.
jshell> "Hello".toUpperCase().indexOf("O");
$49 ==> 4
- Use the backreferences. Usually only used when I forget about semicolon insertion, and accompanied by me kicking myself.
jshell> "Hello".toUpperCase()
$51 ==> "HELLO"
jshell> $51.indexOf("O")
$52 ==> 4
- Move your dots. A bit surprising-looking but works OK. Least-worst option IMHO.
jshell> "Hello".toUpperCase(). // incomplete expression
...> indexOf("O")
$50 ==> 4
NB there is an open bug to prevent this behaviour during multi-line paste
Pasting content
There seems to be a bug which prevents pasting more than 2 lines of code. It’s reported here. That bug is marked as RESOLVED
but still the bug persists in JDK 9.0.1 which is the latest one (on Linux at least). The workaround is:
jshell> /edit
This launches your $EDITOR
which you can paste as many lines as you like into, then save & exit and jshell
evaluates it all.
Conclusion
jshell is a nice way to play with Java code. Much nicer than creating dummy classes with a main()
method. Trisha Gee shows us a nice demo of how to use jshell from IntelliJ - looks great, and I assume other IDEs have similar support. Try it out :)