JShell is an interactive Java prompt: you type a line, it evaluates the line, and it prints the result. There is no class declaration, no main method and no compile step in the middle, which removes almost all the friction between "what does this expression do" and "what does this expression do".
How do I start a session?
Run jshell from a terminal and you get a prompt that waits for input.
jshell
| Welcome to JShell -- an enhanced REPL for Java.
| For an introduction type: /help
jshell> 1 + 1
$1 ==> 2
jshell> String name = "Ada";
$2 ==> "Ada"
jshell> name.toUpperCase()
$3 ==> "ADA"
jshell> /exit
Two details carry most of the value. First, an expression on its own is evaluated and displayed, and the result is also assigned to a hidden variable so you can refer to it later — $1, $2 and so on. Second, a declaration is echoed back, which is a cheap way to confirm that the type you got is the type you expected.
Why is it faster than writing a class?
Compare the two workflows. To check what List.of returns for a duplicate value, the class route means creating a file, writing a class, a main method and a print statement, compiling, and running. The JShell route is one line. For anything exploratory — what a method returns, how a collection behaves, whether an expression compiles at all — that difference is the difference between a two-minute detour and a two-second one.
jshell> import java.util.List;
jshell> List.of(1, 2, 3)
$1 ==> [1, 2, 3]
jshell> List.of(1, 1)
| Exception java.lang.IllegalArgumentException: duplicate element: 1
When something throws, the prompt stays alive. That is the second big advantage: an exception is information, not a crash, so you can immediately inspect the state that produced it.
Can I define methods and classes in the prompt?
Yes, and this is where JShell stops being a calculator. A method definition ends at the closing brace, and the shell keeps it for the rest of the session.
jshell> int area(int width, int height) {
...> return width * height;
...> }
| created method area(int, int)
jshell> area(3, 4)
$1 ==> 12
Classes work the same way, and a class defined in one session is visible for the rest of that session, so you can prototype a small design interactively before committing it to files.
Which commands are worth knowing?
/help— list every command;/help <command>explains one./env— show the current classpath and other settings./imports— list everything imported so far, which is a lifesaver when an import is missing./reload— re-read the files in the current session, so you can edit a class on disk and see the change without restarting./reset— clear the session and start over, keeping the classpath./saveand/open— capture a session to a file and replay it later, which turns a throwaway exploration into a replayable script./exit— leave the prompt.
How do I use my own classes?
Put your compiled classes on the classpath and the shell can import them like any library class.
# compile your project
javac -d out src/com/example/Util.java
# start the shell with that output on the classpath
jshell --class-path out
# or start it with a source file directly
jshell src/com/example/Util.java
jshell> import com.example.Util;
jshell> Util.duplicate("ab")
$1 ==> "abab"
This is the pattern that makes JShell worth the minute it takes to learn: compile a class once, then interrogate it interactively. You keep the real implementation and throw away the throwaway test harness.
Where does JShell fit in a normal working day?
It is tempting to treat JShell as a toy, because it feels like a calculator. It is more useful than that, and the pattern that makes it worthwhile is simple: keep the real code in files, and use the shell as a probe for the code you just wrote.
Suppose you have written a parsing method and you are not sure how it behaves on an edge case. Rather than writing a throwaway class with a main method, compiling it, and deleting it afterwards, you put the compiled class on the classpath and ask the shell directly.
jshell> import com.example.Parser;
jshell> Parser.parse("")
$1 ==> []
jshell> Parser.parse("a,b,,c")
$2 ==> [a, b, c]
jshell> Parser.parse(null)
| Exception java.lang.IllegalArgumentException: input must not be null
Notice what happened: you discovered that an empty segment is silently dropped, and that a null input throws a specific exception. Both are the kind of detail that is much cheaper to find here than in production.
What should you not use it for?
Two limits are worth keeping in mind. The shell is not a place to build a program — anything longer than a few methods is better in a file, where it can be reviewed, diffed and tested. And a session is transient: when the process ends, everything you typed is gone unless you saved it. That is why /save exists — a saved session is a runnable script you can paste into documentation or hand to a colleague.
# capture a session to a file, then replay it later
jshell session.jsh
jshell --class-path out session.jsh
Used that way, the shell becomes a documentation tool as much as an exploration tool: the transcript shows the inputs, the outputs and the errors, which is exactly what a reader needs to understand what a piece of code does.
Quick reference
jshellstarts the prompt;/exitleaves it.- Expressions are evaluated and their results are bound to
$1,$2, … - Methods and classes can be defined in the session and stay available.
/reloadre-reads files,/resetclears the session,/envshows the classpath.--class-pathputs your own compiled classes in reach.- Exceptions do not end the session — read the message, inspect the state, keep going.
Try it yourself: start JShell and work through three experiments: build a HashMap and print it, call a method that throws and catch the exception, then define a small class and instantiate it. When you are done, use /save to capture the session, and rerun it later with /open to see the whole thing replay.