Exploring auto-completion and session-installation features

In Part 1 of this tutorial, I showed you how to use JShell effectively for most common use cases in order to learn about new Java features, APIs, prototype methods and classes, and most of the commands.

In this tutorial, you’ll learn how to:

  • Use the auto-completion feature to discover how to code repetitive snippets faster for experimentation
  • Add external JAR files and classes to the current JShell session CLASSPATH
  • Add modules to the current session MODULEPATH

So, what are you waiting for — let’s jump in.

Working with exercise files

I encourage you to follow along with me, so grab the exercise files by cloning the repository from here:

git clone https://github.com/mohamed-taman/Java-SE-Code-Examples.git

After cloning, navigate to folder 12/jshell and from there start a new JShell session.

Discovery with auto-completion

One of the tools JShell offers that can help you write code is the auto-completion feature. When you partially type the name of an existing class, variable, or method then press the Tab key, JShell performs the magic trick of auto-completing identifiers, snippets, and JShell commands.

What can be done with the Tab key

Pressing the Tab key in JShell performs one of the following tasks:

  • If no other name matches what you’ve typed so far, JShell enters the rest of the name for you
  • If there are multiple names that begin with the same letters, JShell displays a list of those names to help you decide what to type next — then you can type the next letter(s) and press Tab again to complete the name
  • If no names match what you typed so far, nothing happens and an alert sound plays as feedback

Auto-completion identifiers

First load the snippets you saved in a file called MySnippets.txt from the source code folder. To load those snippets, type the command /open then type the two letters My then press the Tab key and it will complete the filename for you. Press Enter to open the MySnippets.txt file and discover its contents:

jshell>/open MySnippets.txt
Mohamed Taman

then

jshell>/list

1 : public class Person {

       private String name;

       public void setName(String name){

              this.name = name;
       }

       public String getName(){
              return name;
       }
       }
2 : Person person;
3 : person = new Person()
4 : new Person()
5 :person.setName("Mohamed Taman")
6 :person.getName()
7 :System.out.println(person.getName())
8 : String name = person.getName();

The only variable declared so far that begins with lowercase p is a person, which was declared in snippet 2. Auto-completion is case sensitive, so p does not match the class name Person. So, if you type p then press Tab, JShell completes the name:

jshell>person

If you enter a dot after the snippet and then press Tab:

jshell> person.
equals(       getClass()    getName()     hashCode()    notify()      notifyAll()   setName(      toString()    wait(

JShell does not know what method you want to call so it displays a list of everything. In this case, all the methods that can appear to the right of the dot.

The list includes the methods we declared in class Person (snippet 1) and several methods inherited from the Java Object class. In the list of method names:

  • Methods followed by “()”do not require arguments
  • Methods followed only by “(”either require at least one argument or overloaded methods

To change the name stored in the person object to MohamedTaman, since there’s only one method that begins with s, you can type s then Tab to complete setName. JShell will automatically insert the method call and now you can complete the snippet:

jshell>person.setName("Mohamed Taman")

Auto-completion commands

Auto-completion also works for JShell commands. If you type / then press Tab, JShell displays the list of JShell commands. If you then type h and press Tab, JShell displays only the commands that start with /h.

Finally, if you type i and press Tab, JShell auto-completes /history. Similarly, if you type /l then press Tab, JShell auto-completes the command as /list because only that command starts with /l.

Discovery of class members and documentation

When using JShell for experimentation and discovery, you may often want to learn more about a class before using it, so let’s explore the Math class.

Listing the Math class’s static members

Start a new JShell session or /reset the current one. As we know, the Math class contains only static members for various mathematical calculations and the static constants PI and E. To view a complete list, type Math. then press Tab.

jshell> Math.

As you know, JShell auto-completion displays a list of everything that can appear to the right of the dot. Since the names that are not followed by any parentheses (for example, E and PI) are the class’s static variables, you can easily view their values:

jshell>Math.PI
jshell>Math.E

Viewing a method’s parameters

Let’s assume you wish to test Math’s pow method but you do not know the parameters it requires. You can type Math.p then Tab to auto-complete the name pow:

jshell>Math.pow(

You can press Tab to view the method’s parameters:

jshell>Math.pow(
Signatures:
double Math.pow(double a, double b)

<press tab again to see documentation>

JShell displays the method’s return type, name, and complete parameter list followed by the next jshell> prompt containing what you’ve typed so far.

Viewing documentation for methods

JShell integrates the Java API documentation so you can view the documentation conveniently in JShell rather than having to use a web browser to read it. Suppose you’d like to learn more about pow before completing your code snippet.

You can press Tab again to view the method’s Java documentation (known as its Javadoc):

jshell>Math.pow(

For long documentation, you can press Tab to view the next page of documentation.

For public fields documentation

You can use the Tab feature to learn more about a class’s public fields if you enter Math.PI followed by Tab:

jshell>Math.PI
Signatures:
Math.PI:double

<press tab again to see documentation>

This shows Math.PI’s type and indicates that you can use Tab again to view the documentation.

jshell>Math.PI
Math.PI:double
The double value that is closer than any other to pi, the ratio of the circumference of a
circle to its diameter.

For class documentation

To view the class’s fully qualified name, typing Math then Tab shows:

jshell> Math
Math          MathContext

Signatures:
java.lang.Math

This indicates that class Math is in the package java.lang. Pressing Tab again shows the beginning of the class’s documentation and pressing Tab once more shows the remaining documentation.

Learn about overloaded method

The method Math.abs has four overloads. When you press Tab, JShell will display the complete list of overloads, showing the parameters for every abs overload:

jshell>Math.abs(
Signatures:
intMath.abs(int a)
long Math.abs(long a)
float Math.abs(float a)
double Math.abs(double a)

Tab again shows the first overload’s documentation. Press Tab again to view the next overload documentation in the list.

Exploring members of a specific object

The Tab key also applies to the members of a specific object. Let’s create and explore a String object:

jshell>vardayName = "Monday"
dayName ==> "Monday"

To view the methods of the dayName object, type dayName. and press Tab:

jshell>dayName.

Now let’s explore the toUpperCase method with dayName., so type toU and press Tab to auto-complete its name:

jshell>dayName.toUpperCase(

Then type Tab to view its parameters:

jshell>dayName.toUpperCase(
Signatures:
String String.toUpperCase(Locale locale)
String String.toUpperCase()

Use the no-argument version to create a new string containing MONDAY by simply entering the closing right parenthesis of the method call and press Enter:

jshell>dayName.toUpperCase()
$2 ==> "MONDAY"

Working with CLASSPATH

Now let’s see how to import classes and add packages to the CLASSPATH.

When working in JShell, you can import any types from Java 12 packages. In fact, JShell automatically imports the packages most commonly used by Java developers. Run the following command to see the current session’s list of packages:

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.*

The java.lang package contents are always available in JShell, just as in any Java source code file. In addition to the Java API packages, you can import your own or third-party packages to use their types in JShell.

In order to import the third-party packages, you need first to use JShell’s /env-class-path command to add the packages to JShell’s CLASSPATH, which specifies where the additional packages are located. You can then use import declarations to experiment with the package contents in JShell.

Let’s add the Person class to JShell’s CLASSPATH. Also, I have downloaded a Gson library JAR file to add to CLASSPATH too so you can use the Gson class to generate a JSON-formatted text from person class instance.

Adding a Gson JAR file to the CLASSPATH

Use the following command to add packages and libraries to the current JShell session’s CLASSPATH:

jshell> /env -class-path ./lib/gson-2.8.5.jar
|  Setting new options and restoring state.

The dot indicates the current folder from which you launched JShell. You also can specify complete paths to other folders on your system or the paths of JAR files that contain packages of compiled classes as I did here.

Importing the Person class to JShell

Now, we can import the Person class for use in JShell:

jshell>/open Person.java

Import the gson package types:

jshell>import com.google.gson.*

and the complete list of imports in the current session:

jshell>/imports
|    import java.io.*
......
|    import java.util.stream.*
|    import com.google.gson.*

Using the imported classes Person and Gson

Finally, you can use the classes Person and Gson. Create a person object, setting the person name:

jshell>var person = new Person()
person ==> Person@5387f9e0

jshell>person.setName("Mohamed Taman")

Create a Gson object:

jshell>Gsongson = new GsonBuilder().create()
gson ==> {serializeNulls:false,factories:[Factory[typeHier ... e8cb],instanceCreators:{}}

Pass the person object to the toJson method of a gson object to generate the JSON schema of the person object:

jshell>gson.toJson(person)
$8 ==> "{\"name\":\"Mohamed Taman\"}"

And that’s all there is to that.

Working with MODULEPATH

You’ve worked with packages, but what if you need to test modules? Here I will show you how to add a module to the current JShell session and import a class from a module’s exported package. First, let’s add a module to the JShell session.

Add java.logging module to the JShell session

To use the logging functionality before the module system that was introduced in Java SE 9, you would normally import the Logger class from the java.util.logging.* package.

This method is no longer valid because Java logging resides in its own java.logging module now.

There are two ways to add modules to JShell. You do the first one when you start JShell by using the following command:

mohamed_taman:jshell$ jshell --add-modules java.logging

You can also add modules from inside the JShell session using the /env command, specifying the module path and the specific modules that JShell should load from that path. For the java.logging example , use this command:

jshell> /env --add-modules java.logging

Note: The --module-path option could be used to indicate where the modules you wish to load are located. I didn’t use this option because I am using a normal JDK module.

Importing a class from a module’s exported package

Once the module is loaded, you may import types from any of the module’s exported packages. This command imports the module’s logging classes under java.util.logging package:

jshell> import java.util.logging.*

At this point, you can use class Logger just as you used other classes before. Create a Logger object:

jshell> Logger log = Logger.getLogger("DevelopersWork JShell Session")
log ==>java.util.logging.Logger@3f0ee7cb

Next, inspect its members with auto-completion by typing log. and pressing Tab:

jshell> log.

To view just the members that begin with i, type i then press Tab:

jshell>log.i
info(  isLoggable(

jshell> log.in

Finally, type n then press Tab to auto-complete the info() method, add your message, then press Enter to invoke the method to print your message:

jshell>log.info("Logging Module is added to JShell successfully")
Jan 08, 2019 1:37:47 AM REPL.$JShell$22 do_it$
INFO: Logging Module is added to JShell successfully

Feedback modes

JShell has several feedback modes that determine what gets displayed after each interaction. To change the feedback mode, use JShell’s /set feedback command:

jshell> /set feedback {mode}

Mode can be normal (the default), concise, silent, or verbose.

verbose mode

This is a new JShell session in which I used verbose mode, one which beginner programmers might prefer:

jshell> /set feedback verbose
|  Feedback mode: verbose

jshell>int x = 10
x ==> 10
|  created variable x : int

jshell>intcube(int y) {return y * y * y;}
|  created method cube(int)

jshell> cube(x)
$14 ==> 1000
|  created scratch variable $14 : int

jshell> x = 5
x ==> 5
|  assigned to x : int

jshell> cube(x)
$16 ==> 125
|  created scratch variable $16 : int

concise mode

Now you can /reset the session and set the feedback mode to concise and repeat the preceding session:

jshell> /set feedback concise
jshell>int x = 10
jshell>intcube(int y) {return y * y * y;}
jshell> cube(x)
$3 ==> 1000
jshell> x = 5
jshell> cube(x)
$5 ==> 125
jshell>

As you can see, the only feedback displayed is the result of each call to the cube method. If an error occurs, its feedback also will be displayed.

silent mode

Next, /reset the session again and set the feedback mode to silent and repeat the preceding session:

jshell> /set feedback silent
->int x = 10
->intcube(int y) {return y * y * y;}
-> cube(x)
-> x = 5
-> cube(x)
-> /set feedback normal

In this case, the jshell> prompt becomes -> and only error feedback will be displayed. You might use this mode if you’ve copied the code from a Java source file and want to paste it into JShell but do not want to see the feedback for each line.

Behind the scenes

So how does JShell re-interpret Java for interactive use?

In JShell:
The main method is not required. And semicolons are not required on standalone statements.
Variables do not need to be declared in classes or in methods. Methods do not need to be declared inside a class’s body. And statements do not need to be written inside methods.
Re-declaring a variable, method, or type simply drops the prior declaration and replaces it with the new one, whereas the Java compiler normally would report an error.
You do not need to catch exceptions, though you can if you need to test exception handling.
JShell ignores top-level access modifiers (public, private, protected, static, final). Only abstract is allowed as a class modifier.
The synchronized keyword is ignored.
Package statements and Java 9 module statements are not allowed.

Summary

In this tutorial, you have learned how to use auto-complete effectively to speed your learning curve for new Java features. You’ve also discovered how to add external JAR files, classes, and modules to your current JShell session via CLASSPATH and MODULEPATH.

These techniques should make learning the features of new JDK versions easier and, hopefully, more fun for you.