これは Java Advent Calendar 2015 の3日目です。昨日は@kawasima さんの「Webアプリ開発/テストのお供に『WAITT』」で、明日は @akihyro さんです。
もしもLLが使えたなら
業務にWindowsを使用していて、開発言語はもっぱらJava、LLを使えたらかっこいいと思うけど、Windowsだし。。。。Powershellとかよく知らないしでもっぱらサクラエディタ、、、そんな方はいらっしゃいませんか?
僕は、そんなあなたを応援します!なぜなら僕がそうだからです!
僕は大量のファイルを作ったり、複雑なファイル検索をしたいなどのデータ処理に、よくJDK付属のjrunscriptコマンドを使っています。例えばこの記事でも使っています。
jrunscriptとは
jrunscriptはJDK6以上に付属しているコマンドで、JVM上でJavaScriptエンジンを実行することが出来るコマンドラインツールです。cd()やdir()などの若干のシェル的な組み込み関数をバンドルしています。
JavaScriptなら、Web開発を経験していれば、Javaばかりの人も自由に書けるのではないでしょうか?
Javaプログラマーがjrunscriptコマンドを使いこなすメリット
- JDKさえ入っていれば、WindowsでもMacでもLinuxでも動く
- 使い慣れたJavaAPIが使える
冒頭に述べた僕みたいな人にぴったりなツールです。確かに、LLに比べてJavaScriptはfunctionなどの入力量が多いです。
しかし、APIを調べたり、言語仕様を勉強している時間がほぼいらないので、やりたいことが最短で実現できます。
しかも、LinuxやMacにそのまま持っていけます!やった\(^o^)/
JVMの状態を見よう
jrunscriptのもう一つの用途として、即座にJavaのシステムプロパティどうなっているんだっけ?など、JVMの状態をしれてしまうことがあります。
$ jrunscript -e "print(java.lang.System.getProperty('user.timezone'))"
システムプロパティを列挙するならこんな感じです。
$ jrunscript -e "for (var key in java.lang.System.properties) print(key + "-" + java.lang.System.properties[key]);"
組み込み関数を知ろう
次のURLに記載された関数が組み込まれています。
http://docs.oracle.com/javase/7/docs/technotes/tools/share/jsdocs/GLOBALS.html
これらの関数は地味ながら、時々役立ちます。例えばjrunscriptで簡単なインストーラーを作るときなどは重宝すると思います。
JavaとJavaScriptの橋渡し
JavaAPIを使ってしまうと、Javaの配列を受け取ったりします。Nashorn/Rhinoの世界では、JavaScriptの配列とJavaの配列は明確に区別されており、JavaScriptとして使うならJavaScript配列を使ったほうが便利です。
例えば、次のようにES5風のforEachが書けます。
nashorn> [1,2,3,4,5].forEach(function(i){print(i);})
1
2
3
4
5
しかし、Java配列の場合はできません。
nashorn> new java.io.File(".").list().forEach(function(i){print(i);})
script error: TypeError: [Ljava.lang.String;@5a63f509 has no such function "forEach" in <STDIN> at line number 1
この場合は、Java.from
というメソッドが使えます。
nashorn> Java.from(new java.io.File(".").list()).forEach(function(i){print(i);})
aaa.txt
bbb.js
xxx.zip
応用編
あるディレクトリ以下の全てのファイルを探索
これはよく使うのでイデオムではないでしょうか。
function f(i) {
if (i.isDirectory()) {
Java.from(i.listFiles()).forEach(function(e) {f(e);})
} else { doSomething(i) }
}
doSomething = function(i) {print(i);};
f(new java.io.File("."));
以下、このfを定義していたとします。
例題1. あるディレクトリ以下で、拡張子がjavaのファイルで10日以内に変更したファイル一覧を取得
doSomething = function(i) {
if (i.lastModified() > java.lang.System.currentTimeMills() - 1000 * 3600 * 24 * 10) {print(i);}};
f(new java.io.File("."));
例題2. あるディレクトリ以下で、ファイル名がAdminから始まっているファイルの容量の合計
doSomething = function(i) {
if (i,getName().startsWith("Admin")) {print(i.length()); sum += i.length()}};
var sum = 0; f(new java.io.File(".")); print(sum);
例題として微妙ではありますが、関数を組み立ててやりたいことを実現していくのが気持ち良くなってきませんか?
まとめ
このように、JDKさえあれば使える、クロスプラットフォームなスクリプティングツールとして、いざというときに役立つのではないでしょうか。
Java6がリリースされてから9年経ちますので、9年前以降のしすてむであったら使うことが出来ます。
JavaAPIが使えるので、いちいち慣れない言語のAPIを調べる手間が省けるのが嬉しいです。あれ、これ、Rubyではどう書くんだろう?と思う必要がありません。
また、ある程度うまく行ったら、Javaで同等なことが出来るので、本番のコードとして流用することもあるかも知れません。
これで、LL弱者の僕も、ワンライナーを駆使できるようになりました。
次はあなたの番です!
jjsコマンドについて
jrunscriptの他に、Java8からはjjsというコマンドが搭載されています。jrunscriptは試験的に作られたコマンドという位置づけなので、本来はjjsコマンドを使うべきです。
しかし、標準組み込み関数が微妙に異なることと、java6,7環境も依然として存在すると思われますので、僕はjrunscriptを好んで使います。