連載
» 2017年09月26日 05時00分 公開

Dev Basics/Keyword:JShell

JShellはJDK 9で導入されたJava用のREPL環境。Javaで書かれた「スニペット」を対話的に入力していくことで、その評価結果を即座に知ることができる。

[かわさきしんじ,Insider.NET編集部]
「Dev Basics/Keyword」のインデックス

連載目次

 JShellはJavaのコードを対話的に評価/実行可能なREPL(Read−Eval−Print Loop)環境。2017年9月21日にリリースされたJDK 9より導入された。

JShellの概要

 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");
  }
}

Hello Worldプログラム(Java)

 これに対して、REPL環境があれば、Hello Worldプログラムは次のようにできる。Javaコードの評価/実行が簡単ですぐにその結果が得られることは、Javaを学習するだけではなく、実際のプログラム開発においても、上のコードに示したようなクラスやメソッドを宣言することなくコードの挙動を確認できるようになる点で有用だといえるだろう。

jshell> System.out.println("Hello World");
Hello World


JShellを使用したHello World

 そこでオフィシャルなREPL環境としてJDK 9ではJShellが導入されることとなった。以下ではJShellの使い方について簡単に見ていこう。なお、本稿ではWindows版のJDK 9を使用している。

JShellの使い方

 JDK 9をインストールすると、javacコマンドなどと同一のディレクトリにjshellコマンドもインストールされる。そのため、「JDK 9のインストールディレクトリ\bin」ディレクトリにパスが通っていればコマンドプロンプトなどで「jshell」と入力することで、JShellが起動する。

JShellの起動画面 JShellの起動画面

 JShellのプロンプトに対しては「Javaコードとして正しい宣言、式、文」を入力できる。例えば、コンソールに「Hello World」と出力するには次のように「System.out.println("Hello World")」と入力する(行末のセミコロンは省略可能)。

JShellでのHello Worldの実行 JShellでのHello Worldの実行

 このようにして入力されたJavaコードフラグメントのことをスニペットと呼ぶ。スニペットにはIDや名前(スニペット名)が割り当てられ、JShell内ではそのIDや名前を利用して、スニペットの削除や編集などが行える。もちろん、クラスも宣言できるし、クラス外(JShellの実行コンテキスト内)でメソッドを宣言することもできる。例えば、以下のようなsayHelloメソッドを宣言するとしよう。

void sayHello(String whom) {
  System.out.println("Hello " + whom);
}

sayHelloメソッド

 これには、プロンプトに対して、そのまま上のコードを入力していけばよい。

JShellでのメソッドの宣言 JShellでのメソッドの宣言

 上の画像にある通り、メソッドを宣言すると「次を作成しました: メソッド sayHello(String)」といったメッセージが表示される。また、上のスニペットには「sayHello」というスニペット名でアクセスが可能だ(後でこれを実際に行ってみよう)。では、次に「sayHello("Insider.NET")」と入力して、このメソッドを実行してみる。このときには[Tab]キーによる補完が行える。以下は「say」まで入力して[Tab]キーを入力したところだ。

[Tab]キーによるコードの入力補完 [Tab]キーによるコードの入力補完

 この場合は「say」にマッチするものがsayHelloメソッド以外にないので、一気に補完が完了して、引数の記述ができるようになっている。続けて、引数を記述して実行したのが以下の画面だ。

sayHelloメソッドの実行画面 sayHelloメソッドの実行画面

 ここでもう一度、このメソッドを呼び出してみよう。その方法には幾つかある。もちろん、[↑]キーを押して、これまでに入力してきた履歴を表示していくことも可能だし、あらためて「sayHello("……")」と入力してもよい。だが、ここではJShellに対するコマンドを使ってみよう。まずは「/list」と入力してみよう。

/listコマンドでこれまでに入力してきたJavaコードのスニペットとそのIDを表示 /listコマンドでこれまでに入力してきたJavaコードのスニペットとそのIDを表示

 /listコマンドは、これまでに入力してきたJavaコードのスニペットとそのIDを表示するものだ(上書きや削除され、IDがなくなったスニペットは表示されない。全てのスニペットを表示するには「/list -all」コマンドを実行する)。左端にあるのがそのスニペットのIDとなる。そして「/ID」とすることで、そのスニペットを再実行できる。よって、「/3」とプロンプトに入力すれば、先ほどのsayHelloメソッド呼び出しを再実行できる。これを行ったのが以下だ。

「/3」コマンドによるスニペットの再実行 「/3」コマンドによるスニペットの再実行

 また、先ほどこのメソッドには「sayHello」というスニペット名でアクセスできるとも述べた。例えば、「/drop sayHello」とすればメソッドを削除できる。メソッドの内容を編集したければ「/edit sayHello」とすればよい(名前ではなくIDを指定することも可能)。例えば、以下はsayHelloメソッドの内容を編集しようとして「/edit sayHello」コマンドを実行したところだ。

「/edit 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コードを記述する際には手放すことができないツールだ。

参考資料


「Dev Basics/Keyword」のインデックス

Dev Basics/Keyword

Copyright© 1999-2017 Digital Advantage Corp. All Rights Reserved.

@IT Special

- PR -

TechTargetジャパン

この記事に関連するホワイトペーパー

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。