Java 9 - JShell in Action


Hi, I am Malathi Boggavarapu working at Volvo Group and i live in Gothenburg, Sweden. I have been working on Java since several years and had vast experience and knowledge across various technologies. In this tutorial we will learn the most important and useful Java 9 feature JShell. So let's jump into the course.

JShell


JShell is a command line application bundled with JDK 9.

Never before did Java ship with such tool which give immediate feedback on code. You can use JShell to quickly test out new ideas or see what an API in jdk behaves the way you think it does. Regular expressions and also for example data and formatting API's are notorious in this regard. Interactive tweaking is a lot better than the slow added compile and run cycle for these things. 

Second Jshell is great way to explore new API's. With code completion and even documentation at tip of your fingers, you can find your way in new API's in minutes. As we have seen these API's can come from any libraries that you put in the classpath, not just jdk API's.

Last, Jshell will help many java programmers get started. whenever you need to show your colleague about something new in Java language, think of Jshell as quick way to do so.

Finally Jshell is nice tool to work with. 

To start jshell, open the command editor and type in jshell.
To exit the jshell is easy. Just type /exit and jshell will terminate. We can also use Ctrl-D to exit jshell

Basics

jshell> 1 + 1
$1 ==> 2

We can type any valid expression of java. After you press enter, Jshell will evaluate the snippets of code and prints back the result. Jshell really shines when you quickly wants to try out snippets that you dont really know from top of your head. So how about doing some bit shift then.

jshell> 4  <<  9
$2  ==> 2048

Bit shifting is one of those things you dont do very often and if we need to do it, this is the great way to play around with some examples and see how all the bitwise operators in java work. You might have noticed another fact, jshell does not only print the result, it also prints the identifier before the arrow. You can use this general identifer values to refer back to the value in the later expressions. So we can refer back to the result of the previous bit shift operation by using $2.

we can try it out as follows

jshell > $2 >> 9
$3 ==> 4

Use Ctrl-l ('L' to be more clear) to clear the screen

Statements

We can also execute statements in jshell. We can illustrate this by calling System.out.println










In the above picture of jshell, when we type Sys and hit "tab", it shows the availability of Sys and shows System.

Later you can type System.out.print and hit "tab", it shows the available methods that could be called on the object. you can see we have print, printf and println methods.
So "tab" is very useful in this case to know the properties and methods of a class

Finally if we type System.out.println("Hello! World") in jshell command prompt, it displays the result. One important point to note regarding Statements is, jshell does not return identifier for statements like it does while we use expressions. And also we no need to add semi-colon at the end of the statement because jshell automatically does this for us.

Lets try with one more statement Thread.sleep(10). If we call sleep method with more time, the main thread will block jshell and we can not use it. But in such cases, we can always quit or go back to jshell prompt by hitting CTRL-C

jshell > Thread.sleep(10)
As we all know, when we call this method, it should throw checked exception but jshell does not throw exception because the it is automatically handled by it.

But we can also handle the exceptions on our own by adding try and catch blocks. We will see that later.

Now if we type Thread.sleep( and hit TAB, the below will be displayed.



It shows all the available overloaded methods of sleep along with its signatures. If we hit TAB again, it shows the documentation of the first method. That is, it shows the documentation about the first method Thread.sleep(long mills). See below



Hitting TAB again, it will show the javaDoc for the second overloaded method.
Jshell provides javaDoc support inline so there is no need to switch to the browser to see java docs. It's all there. This is one of the most useful features of jshell.

I want to give one more example to illustrate the power of JShell. It relates to regular expressions













We can try many such examples. This example shows how easy it is to do meaningfull work inside jshell. we no need to create a whole class, compile and run just to test out small features.

JShell Declarations

Every command in jshell starts with slash (/).
You can explore all the available commands by using the /help command. Lets use the set command to increase the level of feedback that jshell gives for us. This gives us more insight about what's happening inside the jshell for each command that we execute.

jshell> /set feedback verbose
| Feedback mode: verbose

Now let's look at variable declarations in JShell. We will discuss the declarations which were depicted in the below picture.




















We can declare variables as we do in java. In the above picture, we did the following

Declared a variable x and assigned a value 1.
Changed the value of x to 2
Without declaring a variable y, we assigned the value directly. But it throws compilation error. Its obvious!!
We can use /vars command to see the variables that are declared. In the above picture if we see, only one variable x is declared.

How we do Method declaration?
























If you see the above picture, we have done the following

We created a method called whichModule which takes the parameter as Class and returns Module and we all know Module is the concept in modular system in java 9

Next we type whichModule( and hit TAB - Jshell returns all the available overloaded methods. In this case, as we have only one method whichModule, it simply returns that.

Next we type whichModule(String.class) where String is the class that exists inside java.base module in the jdk. So Jshell returns java.base module along with $4 identifier.

Next we tried passing  java.util.logging.LogManager.class as a parameter to whichModule method. So why we need to pass LogManager class with its fully qualified class name? Because Jshell imports only certain packages by default. As LogManager does not exists inside java.base module, if we try to execute without package name, Jshell throws an error. As you can see it returns the result perfectly when we pass LogManager class with its fully qualified class name.

If we want to check what packages are imported by default by the Jshell, we can use command /imports. This list all the packages that were imported by default by the JShell.

We can write our own imports by using import statement as below. As you can see, now we can directly pass the class LogManager without its fully qualified class name. It works!!









We can get the overview of the declared methods with /methods command. Along with whichModule that we created earlier, it also shows printf() method because it is the default method available at all the times in JShell.

Now methods in JShell can also refer to other declarations. It is illustrated in the below picture.



We declared a method timesTwo with parameter i. And inside the method we are doing some simple multiply operation i * x. Here x is already declared earlier so the method can refer to variable x with out any problem. But interesting feature of JShell is we can also reference variables that were not yet declared.  We will see that shortly.






















In the above example, the following things happen.

We created a new method timesThree which accepts variable i and multiplied it with variable three but variable three is not yet declared. But still JShell does not throw error. It means that we can declare the variables at later point of stage after the method is created.

If we try to call the method with some value, Jshell just returns a warning message.

Next if we declare variable three and assign some value and now if you call timesThree(2) then JShell returns the appropriate result.

Class declaration

We can also declare Classes inside JShell. For example we create a Class Person with single field and toString method. see below example. The output will be the result of the toString method. It also creates a reference variable $16 to refer at later point of time.




















We can know interface or class decalrations by using /types command.
Methods and Classes can refer to definitions that are not there yet. This supports experimentation and incremental developments which is exactly the goal of JShell

JShell - Environment

So far we have seen JShell in action in relative isolation. We just eneterd small snippets in JShell command line without any further interaction with the environment. But it is also possible to interact with outside environment from JShell. Lets say you have nice interactive session with  JShell and you are happy with the results so far. What you then can do is to use save command to save the session to a file. Simple uses /save with a filename.

/save mySession.jsh

What happens is that JShell writes a file to a file system containing each snippet that you enter as a seperate entry in this file. At a later point in time, when you restart JShell you can use open command with the file name to get back all the definitions that you had from the previous session. The open command evaluates all of the snippets that you have saved in the file that you are opening. That means all the definitions will be restored such as Class definitions, variable definitions and methods definitions and so on. It also means all statements in snippets will be executed again. So if those statements have any side effects, for example; print to console, this will happen again as well. That's something to keep in mind when saving and opening JShell snippet files. Because some side effects such as deleting and creating are not really meant to happen for the second time. So you should take care when to use save and open functionality.

Below picture illustrate how save and open commands works.





Till now we have seen how to open a file containing multiple snippets. But wouldn't it be nice to also be able to open a plain java source files!! thats possible with JShell as well.

For example we have Person.java file, we can open it using open command. After opening the Java file, JShell will evaluate the contents of the file as if we have typed on the console directly.
That means we can see the class definition if we use /types command in JShell. Since the class is now defined inside JShell we can also use it. For example by instantiating the Person class and then assigning some value to field.

The below picture illustrate, how to open the java file in JShell.



Using open command in JShell is a quick and powerful way to use exisitng java code. There is no need to compile it first, JShell can just evaluates the contents of the java file.

We can also explore exisiting compiled class files in JShell. We can do this by setting classpath when starting Jshell. If we want to use apache commons-lang jar, we can simply set it using --class-path in JShell environment. If you see the below picture, we import StringUtils class in the environment. Now if we do StringUtils.left and hit TAB, it shows all the available methods that start with left. And again if we do StirngUtil.leftPad( and it TAB, it shows all the overloaded method signatures of leftPad.

Using leftPad method from StringUtils, we can add padding to the left side of the String. Now if we do as below, leftPad method from StringUtils class which is present in commons-lang package will be executed and results will be displayed.

StringUtils.leftPad("Indispensible", 20);


















This shows JShell will explore libraries as well or your own application code. As long as you put it on classpath, you can use it in JShell. Ofcourse as is always been the case, you are responsible to create consistent classpath. The commons lang does not have any dependencies but if it would have any depenedencies, those need to be in classpath as well to be able to use the classes.

We have seen that Jshell interact with the environment in different ways. you can load and save snippets, you can open source files and you can even interact with compiled classes by adding them to the classpath in JShell.

JShell API

One last way that JShell interacts with environment and it's bit different from the one's we saw previously. It is the JShell API. So far we have seen the interactive command line that JShell offers.
But there is also API that can be used with your application code as well. You can for example use this to create java based shell in your own application or you can use this as underlying logic to implement  code completion functionality. Jshell also dispatches source code analysis which you can re-use as well by using JShell API. You can pass snipetts of code to JShell API and it will return the types for you. And these do not sound like common scenarios. You are not going to use Jshell API directly. But there are types of applications that can definitly benefit from JShell API. Those are IDE's. Through the API, development environments can integrate JShell directly. NetBeans for example has already implemented this where you can open JShell console which has set correct classpath for your current project.  Bringing JShell into IDE make it even more useful.

Here is small example to see how JShell API looks like.















By using Jshell.create(), we can create a JShell execution environment. This execution environment is stateful, it contains all the evaluated expressions and it stores its own state. The most important method in JShell is eval method. Here we are evaluating the snippet declaring a variable i and assigning a value 0. This results in the list of snippet events. These snippetEvent represents the results of parsing snippet that we passed in, indicating for example whether it successfully parses, what the result value is and so on.

Later we call variables method using jshell. Since JShell is stateful, it remembers the variables that are decalred so it returns stream of VarSnippet.

To know more about JShell API, please refer to javadoc.

So that's all about this course. Hope its helpful. Please post your comments and make the session more interactive.

Happy Learning!!

Comments

Popular posts from this blog

Bash - Execute Pl/Sql script from Shell script

Gradle Fundamentals

Load Balancing using Spring Cloud Netflix Ribbon