Java9からJShell
というREPL(対話型の実行環境)が使えるようになりました
main関数などを書かずともコード片を入力すればその実行結果を試すことができます
対話形式以外にもファイルもしくは標準入力でコードを渡すと実行してくれるので、簡単なワンライナーの実行に使ってみようというのがこの記事の内容です
ワンライナーの実行方法
2つの実行方法があります
1つは標準入力経由でコードを渡す方法、もう1つはファイルとしてコードを渡す方法です
以下に出てくるコマンドではjshell
へのパスが通っているものとします
標準入力経由でコードを実行する
標準入力からコードを実行するときは、jshell
の引数に-
を渡すとよいです
渡さなくてもコード自体は実行されますが対話的モードっぽい出力も表示されてしまいます
echo 'System.out.println("Hello, World!")' | jshell -
ファイル経由でコードを実行する
jshell
の引数には複数のファイルを渡すことができ、渡した順番に実行されます
このときそれぞれのファイル間の処理は独立ではなく、1つ目のファイルで定義した変数に2つ目のファイルのコードでアクセスしたりできます
ファイルを作るのはめんどくさいので代わりにBashのプロセス置換(コマンドの実行結果をファイルとして使える)を使ってコードを渡すと以下のような感じになります
対話的なモードで実行されてしまうので、ワンライナーとしては最後に対話モードの終了を表す/exit
や/ex
を付ける必要があります
jshell <(echo 'System.out.println("Hello, World!");/ex') jshell <(echo 'System.out.println("Hello, World!");') <(echo '/ex')
PRINTING
jshell
の引数にPRINTING
を渡すとprint
やprintln
やprintf
がクラス名などがなしでそのまま呼べるようになります
echo 'println("Hello, World!")' | jshell PRINTING - jshell PRINTING <(echo 'println("Hello, World!");/ex')
オプションなどを渡す
標準入力や引数のファイルはそれぞれコードとして解釈されてしまうので、動作が変わるオプション的なものを渡したいときには環境変数やシステムプロパティとして渡したり、無理矢理Javaのコードに変換して動かす必要があります
環境変数
System.getenv().get(環境変数の名前)
で値を取ってきてがんばる
プロパティ
システムプロパティにてきとうに値を入れて参照する
echo 'println(System.getProperty("foo"))' | jshell -R-Dfoo=123 PRINTING -
シェルの``
によるコマンドの結果の展開を利用すれば標準入力を無理矢理受け取るのにも使えます(長さ制限があるので実用的ではないかもしれませんが)
seq 1 10 | jshell -R-Dfoo="`cat`" PRINTING <(echo 'println(System.getProperty("foo"));/ex')
コードとして渡す
最初に変数を定義するようなコード片をがんばって作って、その値を後続の処理で参照する
jshell PRINTING <(echo 'int a = 1234') <(echo 'println(a);/ex')
実践編
とりあえずFizzBuzzのワンライナーを書いてついでにコードゴルフ(ショートコーディング)をしてみました
classやmain関数などを書く必要がないのでスッキリします
ループ版
echo 'int i;for(;++i<101;)println((i%3<1?"Fizz":"")+(i%5<1?"Buzz":i%3<1?"":i))'|jshell PRINTING -
Stream版
echo 'IntStream.range(1,101).mapToObj(i->(i%3<1?"Fizz":"")+(i%5<1?"Buzz":i%3<1?"":i)).forEach(System.out::println)'|jshell -
まとめ
JShell
を使えばワンライナーもある程度は書けそう
標準入力はコードとして解釈されてしまうので、パイプで繋いでテキストを処理したりするのにはそこまで向いていなさそうなのが残念