2 Snippets

JShell accepts Java statements; variable, method, and class definitions; imports; and expressions. These pieces of Java code are referred to as snippets.

Trying Out Snippets

Snippets of Java code are entered into JShell and immediately evaluated. Feedback about the results, actions performed, and any errors that occurred is shown. Use the examples in this section to give JShell a try.

Start JShell with the verbose option to get the maximum amount of feedback available:

% jshell -v
|  Welcome to JShell -- Version 9
|  For an introduction type: /help intro

Enter the following sample statement at the prompt, and review the output that is shown:

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

First, the result is shown. Read this as: the variable x has the value 45. Because you are in verbose mode, a description of what occurred is also shown. Informative messages start with a vertical bar. Notice that both the name and the type of the created variable are shown.

Note:

Terminating semicolons are automatically added to the end of a complete snippet if not entered.

When an expression is entered that doesn't have a named variable, a scratch variable is created so that the value can be referenced later. The following example shows scratch values for an expression and for the results of a method. The example also shows the continuation prompt (...>) that is used when a snippet requires more than one line of input to complete:

jshell> 2 + 2
$3 ==> 4
|  created scratch variable $3 : int

jshell> String twice(String s) {
   ...>    return s + s;
   ...> }
|  created method twice(String)

jshell> twice("Ocean")
$5 ==> "OceanOcean"
|  created scratch variable $5 : String

Changing Definitions

As you experiment with code, you might find that the definition of a variable, method, or class isn’t doing what you want it to do. The definition is easily changed by entering a new one, which overwrites the previous definition.

To change the definition of a variable, method, or class, simply enter a new definition. For example, the twice method that was defined in Trying Out Snippets gets a new definition in the following example:

jshell> String twice(String s) {
   ...>    return "Twice:" + s;
   ...> }
|  modified method twice(String)

jshell> twice("thing")
$7 ==> "Twice:thing"
|  created scratch variable $7 : String

Notice that instead of showing created method as before, the feedback shows modified method. This message means that the definition changed, but the method has the same signature, and therefore all existing usages continue to be valid.

You can also change definitions in incompatible ways. The following example shows x being changed from int to String:

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

jshell> String x
x ==> null
|  replaced variable x : String
|    update overwrote variable x : int

The type of the variable x changed, and the feedback now shows replaced.

Changing the Level of Feedback

JShell was started in the verbose feedback mode, which provides a lot of commentary. You can set the amount and format of output with the /set feedback command, for example /set feedback concise. If you primarily use JShell by pasting from other windows, then you might prefer a feedback mode with no prompt and only error feedback. If so, then enter the /set feedback silent command.

Forward References

JShell accepts method definitions that reference methods, variables, or classes that aren’t yet defined. This is done to support exploratory programming and because some forms of programming require it.

As an example, if you want to define a method for the volume of a sphere, then you can enter the following formula as the method volume:

jshell> double volume(double radius) {
   ...>    return 4.0 / 3.0 * PI * cube(radius);
   ...> }
|  created method volume(double), however, it cannot be invoked until variable PI, and method cube(double) are declared

JShell allows the definition but warns of what is yet to be defined. The definition can be referenced, but if execution is attempted, then it fails until all of the required elements are defined:

jshell> double PI = 3.1415926535
PI ==> 3.1415926535
|  created variable PI : double

jshell> volume(2)
|  attempted to call method volume(double) which cannot be invoked until method cube(double) is declared

jshell> double cube(double x) { return x * x * x; }
|  created method cube(double)
|    update modified method volume(double)

jshell> volume(2)
$5 ==> 33.510321637333334
|  created scratch variable $5 : double

With all of the definitions in place, the volume method now works.

This method is now used to illustrate more about incompatible replacement. For example, to change the precision of PI, enter the new value as shown in the following example:

jshell> BigDecimal PI = new BigDecimal("3.141592653589793238462643383")
PI ==> 3.141592653589793238462643383
|  replaced variable PI : BigDecimal
|    update modified method volume(double) which cannot be invoked until this error is corrected: 
|      bad operand types for binary operator '*'
|        first type:  double
|        second type: java.math.BigDecimal
|          return 4.0 / 3.0 * PI * cube(radius);
|                 ^------------^
|    update overwrote variable PI : double

The new definition of PI is type-incompatible with the definition of volume(). Because you are in verbose mode, update information is shown for other definitions affected by the change, which in this case describes the incompatibility. Notice that verbose mode is the only predefined feedback mode that displays update information. In other feedback modes, no warning is displayed until the code is executed. The purpose of this is to prevent an overload of updates. In all predefined modes, executing the volume() method displays the issue:

jshell> volume(2)
|  attempted to call method volume(double) which cannot be invoked until this error is corrected: 
|      bad operand types for binary operator '*'
|        first type:  double
|        second type: java.math.BigDecimal
|          return 4.0 / 3.0 * PI * cube(radius);
|                 ^------------^

Exceptions

In an exception backtrace, feedback identifies the snippet and the location within the snippet where the exception occurred.

The location within the code entered into JShell is displayed as #ID:line-number, where snippet ID is the number displayed by the /list command, and line-number is the line number within the snippet. In the following example, the exception occurs in snippet 1, which is the divide() method, on the second line of the method:

jshell> int divide(int x, int y) {
   ...> return x / y;
   ...> }
|  created method divide(int,int)

jshell> divide(5, 0)
|  java.lang.ArithmeticException thrown: / by zero
|        at divide (#1:2)
|        at (#2:1)
                             
jshell> /list
                                                            
   1 : int divide(int x, int y) {
           return x / y;
       }
   2 : divide(5, 0)

Tab Completion for Snippets

When you enter snippets, use the Tab key to automatically complete the item. If the item can’t be determined from what was entered, then possible options are provided.

For example, if you entered the volume method from Forward References, then you can enter the first few letters of the method name, and then press the Tab key to complete the entry:

jshell> vol<Tab>

The input changes to the following:

jshell> volume(

If the item can be completed in more than one way, the set of possibilities is displayed:

jshell> System.c<Tab>
class                 clearProperty(        console()             currentTimeMillis()

jshell> System.c

Any common characters are added to what you entered, and the cursor is placed at the end of the input so that more can be entered.

When you are at a method call's open parenthesis, pressing Tab shows completion possibilities with the parameter types:

jshell> "hello".startsWith(<Tab>
Signatures:
boolean String.startsWith(String prefix, int toffset)
boolean String.startsWith(String prefix)

<press tab again to see documentation>

jshell> "hello".startsWith(

Pressing Tab again shows a plain-text version of the documentation for the first method.

jshell> "hello".startsWith(<Tab>
boolean String.startsWith(String prefix, int toffset)
Tests if the substring of this string beginning at the specified index starts with the
specified prefix.

Parameters:
prefix - the prefix.
toffset - where to begin looking in this string.

Returns:
true if the character sequence represented by the argument is a prefix of the substring of this
          object starting at index toffset ; false otherwise. The result is false if toffset is
          negative or greater than the length of this String object; otherwise the result is
          the same as the result of the expression
                    this.substring(toffset).startsWith(prefix)
                    

<press tab to see next documentation>

jshell> "hello".startsWith(

Snippet Transformation

JShell makes it easy to import a needed class when it is first referenced and convert an expression to a variable declaration using keyboard shortcuts.

When you enter an identifier that isn’t imported yet, press Shift+Tab i immediately after the identifier to see the options that enable you to add the import to your session:

jshell> new JFrame<Shift+Tab i>
0: Do nothing
1: import: javax.swing.JFrame
Choice: 1
Imported: javax.swing.JFrame

jshell> new JFrame

Enter the number of the option you want. More than one import option could be provided.

You can convert an expression to a variable declaration by pressing Shift+Tab v after you enter the expression. The expression becomes the initial value of the variable declaration, and the type of the expression becomes the type of the variable. After you press Shift+Tab v, the cursor, which is indicated by a vertical bar (|) in the example, is placed in the line where you need to enter the variable name:

jshell> new JFrame("Demo") <Shift+Tab v>
jshell> JFrame | = new JFrame("Demo")

Note:

The expression must be valid or the transformation request is ignored. In the example, the import of JFrame is required before the variable transformation.

To complete the previous example, enter the variable name frame at the cursor and press Enter:

jshell> JFrame frame = new JFrame("Demo")
frame ==> javax.swing.JFrame[frame0,0,0,0x0,invalid,hidden, ... tPaneCheckingEnabled=true]
|  created variable frame : JFrame

jshell>

Sometimes the result type of the expression isn’t imported yet. In that case, Shift+Tab v offers to both import and create the variable, as shown in the following example:

jshell> frame.getGraphics() <Shift+Tab v>
0: Do nothing
1: Create variable
2: import: java.awt.Graphics. Create variable
Choice: 2
Imported: java.awt.Graphics

jshell> Graphics | = frame.getGraphics()

To complete the previous example, enter the variable name gc at the cursor and press Enter:

jshell> Graphics gc = frame.getGraphics()
|  created variable gc : JFrame

jshell>