JShellはJDK 9で導入されたJava用のREPL環境。Javaで書かれた「スニペット」を対話的に入力していくことで、その評価結果を即座に知ることができる。
JShellはJavaのコードを対話的に評価/実行可能なREPL(Read−Eval−Print Loop)環境。2017年9月21日にリリースされたJDK 9より導入された。
JShellは、Javaで書かれた宣言や文、式を評価することが可能な対話的なツールおよびそれをJavaプログラム内から使用するためのAPI(jdk.jshellパッケージ)で構成される。ただし、本稿ではコマンドラインツールとしてのJShellに注目する。
JShellが提案された動機としては、他の多くの言語には存在するREPL環境がJavaにはないことで、プログラミングを学習するための言語としてJavaが選択されにくくなっていることが挙げられている。例えば、「Hello World」プログラムを書くだけでもJavaでは次のようにクラスの宣言(とコンパイル、実行という手順)が必要になる。
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello World");
}
}
これに対して、REPL環境があれば、Hello Worldプログラムは次のようにできる。Javaコードの評価/実行が簡単ですぐにその結果が得られることは、Javaを学習するだけではなく、実際のプログラム開発においても、上のコードに示したようなクラスやメソッドを宣言することなくコードの挙動を確認できるようになる点で有用だといえるだろう。
jshell> System.out.println("Hello World");
Hello World
そこでオフィシャルなREPL環境としてJDK 9ではJShellが導入されることとなった。以下ではJShellの使い方について簡単に見ていこう。なお、本稿ではWindows版のJDK 9を使用している。
JDK 9をインストールすると、javacコマンドなどと同一のディレクトリにjshellコマンドもインストールされる。そのため、「JDK 9のインストールディレクトリ\bin」ディレクトリにパスが通っていればコマンドプロンプトなどで「jshell」と入力することで、JShellが起動する。
JShellのプロンプトに対しては「Javaコードとして正しい宣言、式、文」を入力できる。例えば、コンソールに「Hello World」と出力するには次のように「System.out.println("Hello World")」と入力する(行末のセミコロンは省略可能)。
このようにして入力されたJavaコードフラグメントのことをスニペットと呼ぶ。スニペットにはIDや名前(スニペット名)が割り当てられ、JShell内ではそのIDや名前を利用して、スニペットの削除や編集などが行える。もちろん、クラスも宣言できるし、クラス外(JShellの実行コンテキスト内)でメソッドを宣言することもできる。例えば、以下のようなsayHelloメソッドを宣言するとしよう。
void sayHello(String whom) {
System.out.println("Hello " + whom);
}
これには、プロンプトに対して、そのまま上のコードを入力していけばよい。
上の画像にある通り、メソッドを宣言すると「次を作成しました: メソッド sayHello(String)」といったメッセージが表示される。また、上のスニペットには「sayHello」というスニペット名でアクセスが可能だ(後でこれを実際に行ってみよう)。では、次に「sayHello("Insider.NET")」と入力して、このメソッドを実行してみる。このときには[Tab]キーによる補完が行える。以下は「say」まで入力して[Tab]キーを入力したところだ。
この場合は「say」にマッチするものがsayHelloメソッド以外にないので、一気に補完が完了して、引数の記述ができるようになっている。続けて、引数を記述して実行したのが以下の画面だ。
ここでもう一度、このメソッドを呼び出してみよう。その方法には幾つかある。もちろん、[↑]キーを押して、これまでに入力してきた履歴を表示していくことも可能だし、あらためて「sayHello("……")」と入力してもよい。だが、ここではJShellに対するコマンドを使ってみよう。まずは「/list」と入力してみよう。
/listコマンドは、これまでに入力してきたJavaコードのスニペットとそのIDを表示するものだ(上書きや削除され、IDがなくなったスニペットは表示されない。全てのスニペットを表示するには「/list -all」コマンドを実行する)。左端にあるのがそのスニペットのIDとなる。そして「/ID」とすることで、そのスニペットを再実行できる。よって、「/3」とプロンプトに入力すれば、先ほどのsayHelloメソッド呼び出しを再実行できる。これを行ったのが以下だ。
また、先ほどこのメソッドには「sayHello」というスニペット名でアクセスできるとも述べた。例えば、「/drop sayHello」とすればメソッドを削除できる。メソッドの内容を編集したければ「/edit sayHello」とすればよい(名前ではなくIDを指定することも可能)。例えば、以下はsayHelloメソッドの内容を編集しようとして「/edit sayHello」コマンドを実行したところだ。
編集を終えたら[Accept]ボタンをクリックする。このときにエラーがあれば、その旨がJShellのコンソールに表示されるので、編集ウィンドウでそれを修正しよう。エラーがなければ「次を変更しました: メソッド sayHello(String)」といったメッセージが表示されるので、最後に[Exit]ボタンをクリックすれば、編集ウィンドウが閉じられる。
今見たように、シェルに対するコマンドは「/」を前置して入力する。例えば、JShellを終了するコマンドは「/exit」となる。こうしたコマンドには以下のものがある(抜粋)。なお、これらのコマンド名は一意に識別できればよく、全部を入力しなくてもよい(例えば、「/li」とだけ入力すれば「/list」コマンドを実行してくれる)。
コマンド | 説明 |
---|---|
/drop | スニペットを削除する |
/edit | スニペットを編集する |
/list | これまでに入力したスニペットの履歴を表示する |
/save | スニペットをファイルに保存する。デフォルトではユーザーのホームディレクトリ(「c:\Users\ユーザー名」など)に保存される |
/open | ファイルからスニペットを読み込んで実行する |
/vars | JShell内で宣言された変数を表示する |
/methods | JShell内で宣言されたメソッドを表示する |
/types | JShell内で宣言された型を表示する |
/imports | インポートされたアイテムを表示する |
/history | 入力したスニペットとコマンドの履歴を表示する |
/help | ヘルプドキュメントの表示 |
/exit | JShellの終了 |
/ID | IDで指定したスニペットの再実行(名前の指定も可能) |
/! | 直前に実行したスニペットの再実行 |
JShellのコマンド(一部) |
これらのコマンドにはオプションも指定できる。各コマンドの詳細は「/help list」「/help save」など「/help」に続けてコマンド名を指定すれば、ドキュメントが表示される。1つだけオプションの例を挙げると、/listコマンドの-startオプションがある。これはJShell起動時に自動的に評価されたスニペットを表示するものだ。これを実行した結果を以下に示す。
これを見ると分かる通り、Javaで一般的に使われる各種パッケージが自動的に読み込まれるようになっているのが分かる(これらは/importsコマンドでも一覧できる)。JShellでは、これらのパッケージを読み込んだコンテキスト内で対話的にコードの評価、実行が行われているということだ。
上の表に/varsコマンド、/methodsコマンド、/typesコマンドがあることからも分かるように、JShellでは上で見たメソッドだけではなく、クラスを宣言したり、そのクラスのインスタンスを参照する変数を宣言したりすることも可能だ。最後にこの例を示しておこう。ここではJShellに以下のようなスニペットを入力したとする。
class Foo {
private String name;
private int age;
public String getName() { return name; }
public int getAge() { return age; }
public Foo(String name, int age) {
this.name = name;
this.age = age;
}
public Foo() {
this("noname", 0);
}
}
Foo f = new Foo("kawasaki", 18);
f.getName();
f.getAge();
これを実行したところを以下に示す。
getNameメソッドやgetAgeメソッドを呼び出しているスニペットでは、そのIDと実行結果が表示されていることに注意されたい。また、興味のある方はこの状態で/varsコマンド、/typesコマンドなどを実行して、現在のJShellでどんなものが宣言されているかを確認してみよう。
ここまでに見てきたように、JShellを使うことで、Javaコードを手軽に実行して、その結果を即座に知ることができる。Javaコードを記述する際には手放すことができないツールだ。
Copyright© Digital Advantage Corp. All Rights Reserved.