In Java 8, Oracle introduced the new Nashorn engine and is encouraging the use of jjs. It’s a RPEL (read print evaluate loop) for JavaScript. Since JavaScript can call Java, this allows experimenting with Java APIs like you do in other languages like Python and Ruby. I actively disliked it and even wrote a blog post about what turned me off. Java 9 introduced JShell for this same purpose except it works with Java rather than a level of indirection through JavaScript.
In this blog post, I repeat the same experiment with JShell (using the Java 9 early access download) to see if it is any better. Again I used the exercises from Cay Horstmann’s book, Java SE 8 for the Really Impatient so it would be an equivalent experiment.
Exercise 1 – Play … to experiment with an API you want to explore; did you find it easier than writing test programs in Java?
With Nashorn/jjs in Java 8, I had three issues. Let’s see how jjs compares:
Nashorn/jjs |
JShell |
Strike 1 – needing to type in the package name of classes. |
Better. At least common packages are included now like java.util. For others, like LocalDate, you still need to type the package name. Which often means looking up the package name. I rely heavily on “organize imports” in my IDE for package names. |
Strike 2 – no tab complete |
Success! JShell has tab complete for packages, classes and methods |
Strike 3 – no up arrow support |
Success! JShell lets you you use the up/down arrows to go through your command history. |
Having solved these three issues, the question is a better one. If I’m on a UNIX system or don’t have my IDE open, JShell would definitely be faster. If I already have the IDE open, I have a “PlayTest” program with a main method already available to me so it is a tie. But that’s just my workflow. JShell looks good.
Note: I learned on Twitter that:
wickund: @jeanneboyarsky jjs in JDK9 uses the same API as jshell (JDK9), so there is code completion and up arrow.
Which means my issues with Nashorn are gone in Java 9. Thanks Jim Laskey
Exercise 2 – Using …. the stream library iteratively work out a solution to the problem to print a filtered list of unique long words in sorted order and see how it compares to your usual workflow.
Here was my workflow with JShell:
- Create the test file in a text editor (vi)
- Run ./jshell
- Create a path object
Attempt # |
Code |
Error |
Comments |
1 |
jshell> Path paths = Path.get(“path/words.txt”) |
|
Success! This package is included in the list of known ones so I didn’t even have to look anything up. |
- Read the file
Attempt # |
Code |
Error |
Comments |
1 |
jshell> List<String> list = Files.readAllLines(path) |
|
Success |
- Filter the long words
Worked.
Attempt # |
Code |
Error |
Comments |
1 |
jshell> list.stream().grep({ l -> l.length() > 12}) |
cannot find symbol |
This is completely wrong. Aside from the stream() call, it is using Groovy syntax. (I code Groovy at a command line so my fingers started there. I did the same thing when I was doing this with Nashorn) |
2 |
jshell> list.stream().filter( l -> l.length() > 12) |
|
Success |
- Add sorting and uniqueness
Attempt # |
Code |
Error |
Comments |
1 |
jshell> list.stream().filter(l -> l.length() > 12).sorted().forEach(System.out::println) |
|
Sorting worked |
2 |
jshell> list.stream().filter(l -> l.length() > 12).sorted().distinct().forEach(System.out::println) |
|
Uniqueness filter worked |
My thoughts
This was 6 attempts/iterations using JShell. This is compared to 17 in Nashorn! JShell is clearly a superior tool for prototyping Java. Part of this is because they implement common RPEL features. And part is because they don’t try to shoehorn a rhinoceros into being a Java RPEL. Seriously, many of the problems with Nashorn came from mixing Java and JavaScript while trying to prototype Java.