Was ist die JShell? v.9

Das Java Shell Tool (JShell) ist ein mit Java 9 eingeführtes interaktives Werkzeug zum schnellen Testen von Java Codefragmenten.

Dieser Artikel gibt einen zusammenfassenden Überblick über die Funktionen und Hauptmerkmale der JShell. Auf Grund des Funktionsumfangs kann hier nur eine begrenzte Einführung gegeben werden. Zur ausführlichen Information sei auf die offizielle JShell-Dokumentation von Oracle verwiesen.

Aufgaben der JShell

Im Gegensatz zu einer IDE dient die JShell zum schnellen Ausprobieren kurzer Java-Codefragmente aller Art. Um diese auszuführen, müssen in der JShell weder eine Main-Methode geschrieben, noch ein komplettes Programm aufwändig kompiliert werden. Die Eingabe des zu prüfenden Quelltextes reicht aus. Die JShell stellt ein hierzu ausgezeichnetes und sehr mächtiges Werkzeug dar.

JShell starten und beenden

Die JShell ist seit Java 9 Bestandteil des JDK. Die ausführbare Datei findet sich im bin-Verzeichnis der JDK-Installation.
Für ein im Heimatverzeichnis des Users unter ~/jdk installiertes JDK 11 sieht ein Aufruf der JShell im Terminal folgendermaßen aus:

Eric:~ joecze$ ~/jdk/jdk-11.0.2.jdk/Contents/Home/bin/jshell
|  Welcome to JShell -- Version 11.0.2
|  For an introduction type: /help intro

jshell>

Durch die Eingabe von /exit wird die JShell beendet.

Shellbefehle

Nach dem Start der JShell kann durch Eingabe von /help intro ein kleiner Einführungstext, durch Eingabe von /help eine Auflistung aller Shellbefehle erreicht werden. Sie beginnen immer mit einem '/'. Durch den Aufruf von /help <befehl> wird eine Hilfe zu dem jeweiligen Befehl angezeigt.

jshell> /help list
|
|                                   /list
|                                   =====
|
|  Show the snippets, prefaced with their snippet IDs.
|
|  /list
|  	List the currently active snippets of code that you typed or read with /open
|
|  /list -start
|  	List the evaluated startup snippets
|
|  /list -all
|  	List all snippets including failed, overwritten, dropped, and startup
|
|  /list <name>
|  	List snippets with the specified name (preference for active snippets)
|
|  /list <id>
|  	List the snippet with the specified snippet ID.
|  	One or more IDs or ID ranges may used, see '/help id'

/list zeigt alle bereits eingegebenen Codesnippets. Die Shortcuts /vars, /types und /methods listen die bislang eingegebenen Variablen, Typen und Methoden auf.

Einstellen des Feedback-Modus

Ruft man die JShell mit dem Schalter -v für 'verbose mode' auf, so ist die Ausgabe von Beginn an deutlich ausführlicher.

jshell> int x = 10  // Aufruf im verbose mode
x ==> 10
|  created variable x : int

jshell> int x = 10  // Aufruf im normal mode
x ==> 10

Die Ausführlichkeit der Ausgabe kann recht kleinteilig gesteuert werden. Nach Eingabe von /set feedback wird das derzeitige Feedback-Level angezeigt, gefolgt von einer Liste der diesbezüglich zur Verfügung stehenden Modi.
So kann der Feedback-Modus normal z.B. durch Eingabe von /set feedback normal eingestellt werden.

jshell> /set feedback
|  /set feedback normal
|
|  Available feedback modes:
|     concise
|     normal
|     silent
|     verbose

jshell> /set feedback verbose
|  Feedback mode: verbose

Einen umfangreichen Überblick über die genauen Modusformate erhält man durch Eingabe von /set mode.

Eingabe an der JShell

Jede Eingabe an der JShell wird durch <Enter> beendet. Mehrzeilige, unabgeschlossene Eingaben sind durch ...> am Zeilenanfang gekennzeichnet. Kommentarzeilen beginnen immer mit einem senkrechten Strich.

Meist ist die Eingabe eines Semikolons zum Abschluss eines Ausdrucks nicht erforderlich. Wird dies doch verlangt, so wird in Kommentaren darauf hingewiesen.

jshell> String string() {
   ...> return "Hallo Welt"
   ...> }
|  Error:
|  ';' expected
|  return "Hallo Welt"
|                     ^

jshell> return "Hallo Welt";

jshell> System.out.println(string())
Hallo Welt

Wie hier zu sehen ist, reicht ggf. die Korrektur einer fehlerhaften Zeile aus, um die gesamte Eingabe zu korrigieren. Hier wird das am Fehlen eines Semikolons innerhalb einer Methode demonstriert.

Die History

An die zu korrigierende Zeile gelangt man über die eingebaute History, in der mit Hilfe der Pfeiltasten navigiert wird. ↑ navigiert zurück, ↓ navigiert wieder einen Befehl vor.
Die History kann auch durchsucht werden. <Ctrl r> sucht schrittweise rückwärts von der aktuellen Eingabe aus, <Ctrl s> sucht vorwärts. Nach Eingabe des Shortcuts wird der Suchstring am Prompt eingegeben. Ein Fund wird sofort ohne Drücken von <Enter> angezeigt. Die wiederholte Eingabe des Shortcuts führt die Suche bis zum nächsten Fund durch. Der Suchstring muss nicht nochmals eingegeben werden. Abgebrochen werden kann die Suche durch <Ctrl c>.

Vervollständigungen

JShell unterstützt Code-Vervollständigung durch Drücken von <Tab>. Ist eine Eingabe mehrdeutig, so werden die infrage kommenden Möglichkeiten aufgelistet, sodass durch Eingabe des nächsten Zeichens eine weitere Eingrenzung vorgenommen werden kann.

jshell> System.e<Tab>
err     exit(

jshell> System.err<Tab>
Signatures:
System.err:java.io.PrintStream

<press tab again to see documentation>

Dies funktioniert auch mit Methoden, wobei bei Überladung alle Varianten vorgeschlagen werden.

jshell> Arrays.binarySearch(<Tab>
Signatures:
int Arrays.binarySearch(long[] a, long key)
int Arrays.binarySearch(long[] a, int fromIndex, int toIndex, long key)
int Arrays.binarySearch(int[] a, int key)
int Arrays.binarySearch(int[] a, int fromIndex, int toIndex, int key)
int Arrays.binarySearch(short[] a, short key)
int Arrays.binarySearch(short[] a, int fromIndex, int toIndex, short key)
int Arrays.binarySearch(char[] a, char key)
int Arrays.binarySearch(char[] a, int fromIndex, int toIndex, char key)
int Arrays.binarySearch(byte[] a, byte key)
int Arrays.binarySearch(byte[] a, int fromIndex, int toIndex, byte key)
int Arrays.binarySearch(double[] a, double key)
int Arrays.binarySearch(double[] a, int fromIndex, int toIndex, double key)
int Arrays.binarySearch(float[] a, float key)
int Arrays.binarySearch(float[] a, int fromIndex, int toIndex, float key)
int Arrays.binarySearch(Object[] a, Object key)
int Arrays.binarySearch(Object[] a, int fromIndex, int toIndex, Object key)
int Arrays.<T>binarySearch(T[] a, T key, Comparator<? super T> c)
int Arrays.<T>binarySearch(T[] a, int fromIndex, int toIndex, T key, Comparator<? super T> c)

<press tab again to see documentation>

jshell> Arrays.binarySearch(

Durch weiteres Drücken der Tab-Taste wird bei Bedarf die Java-Dokumentation des zuerst aufgeführten Verweises gezeigt.

Vervollständigungen durch Drücken von <Tab> funktionieren nicht nur bei der Eingabe von Snippets, sondern auch bei den Shellbefehlen selbst und sogar bei deren Argumenten.

jshell> /l<Tab>
jshell> /list -a<Tab>
jshell> /list -all

Drei weitere Tastaturkürzel sind hilfreich beim Coden: Durch Drücken von <Shift+Tab> und anschließendem(!) Drücken von 'i', 'v' oder 'm' kann entweder ein Import vorgenommen (i), der Ausdruck in eine Variable gewandelt (v) oder eine Methodendeklaration vorgenommen (m) werden. Gibt es mehrere Möglichkeiten, so werden diese durch vorangestellte Ziffern gekennzeichnet. Die jeweilige Variante wird nach Eingabe der Ziffer ohne weitere Bestätigung übernommen.

jshell> new Point <Shift+Tab i>
0: Do nothing
1: import: java.awt.Point
Choice: <1>
Imported: java.awt.Point

Das Funktionieren der Vervollständigungen ist etwas 'tricky'. Das eingegebene Code-Fragment muss zum gewünschten Ausdruck passen und ist abhängig vom jeweiligen Vollständigkeitszustand des Ausdrucks.
Die Eingabe von <Shift+Tab i> zum Import einer Klasse ist z.B. nicht erfolgreich nach Eingabe eines Konstruktoraufrufs mit Klammern, während diejenige ohne Klammern nach Eingabe von <Shift+Tab i> zum gewünschten Import führt.

jshell> new Point() <Shift+Tab i>
No candidate fully qualified names found to import.
				
jshell> new Point <Shift+Tab i>
0: Do nothing
1: import: java.awt.Point
Choice:

Der eingegebene Ausdruck muss insbesondere gültig sein, bevor eine Vervollständigung erfolgen kann. So ist eine Transformation zur Variablen z.B. nicht möglich, wenn eine hierzu benötigte Klasse vorher nicht importiert wurde.

Externer Editor

Es kann besonders bei längeren Quelltexten von Vorteil sein, Editierungen in einem externen Editor vorzunehmen. JShell bringt einen eigenen Editor mit, der durch Eingabe von /edit aufgerufen werden kann. Durch die Folgeeingabe eines Snippetnamens oder seiner ID kann ein gewünschter Quelltext direkt im Editor geöffnet werden. Die folgende Eingabe öffnet die Methode quadrat() im externen Editor.

jshell> /list

   1 : int quadrat(int a, int b) {
       int x = a * b;
       return x;
       }
   2 : System.out.println(quadrat(34,18));

jshell> /edit 1
Quellen

https://docs.oracle.com/javase/9/jshell/toc.htm