Nashornのセッションに出だけど、色々分からないのでScript Engineのお勉強1

まえがき

JavaDayTokyo2014 一発目のセッションでは、今まで気になりつつも、触る事が出来ていない、
Nashorn(ナスホーン、ナショーン)のセッションを聴講してきました。
話を聞いてみて、面白いなと思ったものの、

これは実際使ってみないと実感が湧かない(特に実際使うという場面において)

と思いましたので、この記事はセッションのFBも踏まえつつ、「Nashorn試してみた」的なエントリーとの
ハイブリットな投稿になると思います。実際、セッションの冒頭でもNashorn使ってみた人?というアンケートがありましたが、
手を挙げていた人は1割にも満たなかったので、Java8の新機能としてfeatureされつつも、
なかなかまだ実際に使っている人は少ない、という所でしょうか。
自分もその中の一人なので、まずは「Script Engineって何? Nashornって何?」という所から初めていきます。
※ので、結果的にセッション内容のFBに本気記事ではほとんど触れません。

Nashornとは

  • 新しいScript Engineです。
  • Script Engineとは、いわゆるScript言語を実行するEngineです。つまり、JavaにおけるScript Engineは、

Javaからスクリプト言語を呼び出したり(あるいはその逆)の機能を提供するものになります。

ここで一つ注意しておくべきことは、スクリプトエンジン自体は、新しい機能では無いという点です。
Script Engine自体は上記のリンク先にあるように,Java6から提供されています。
なので、新しいScript Engineの一つとして、NashornがJava8から追加されたということですね。

  • Nashornがでる前にデフォルトのEngineとして提供されていたものは、Rhinoという、Mozillaが提供しているスクリプトエンジンでした。

まずはScriptEngine動かす(java8だとデフォルトでNashornを動かす)。

ということで、なんとなくNashorn及びScript Engineのイメージもついたところで、実際に関数を実行してみます。

これ自体はめちゃくちゃ簡単で、すぐに動かせました。
というか、動かし方事態は、Rhinoの時と基本的に全く同じなので、
ScriptEngineに関連する記事はすぐ見つけられました。
で、すぐHello worldが出せました。
使っているEngine名を確認するとNashornと出ているので、無事Nashornが使えていることも確認できます。

        ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
        ScriptEngine engine = scriptEngineManager.getEngineByName("js");
        System.out.println(engine.getFactory().getEngineName());
        try {
            engine.eval("print('HelloWorld!')");
        } catch (ScriptException e) {
            e.printStackTrace();
        }

        //出力
        Oracle Nashorn // Engineの名前はOracle Nashornってことなのかな
        HelloWorld! // printってのがとりあえず標準出力を出す為に提供されているらしい

よしよし。
ところで、
色んなサイトをみると、すぐみんなこのprintって関数使ってHelloWorldやってるんですが、

printって何?

ってなりませんでしたか?僕はなりましたw
で、中身出してみたら、また色々と・・・w
printの中身については別途記事で書きます。

ちなみにprintの中身は下です。
色々気になりますよね?w

function print() {
    var writer = context != null? context.writer : engine.context.writer;
    if (! (writer instanceof java.io.PrintWriter)) {
        writer = new java.io.PrintWriter(writer);
    }
    
    var buf = new java.lang.StringBuilder();
    for (var i = 0; i < arguments.length; i++) {
        if (i != 0) {
            buf.append(' ');
        }
        buf.append(String(arguments[i]));
    }
    writer.println(buf.toString());
}

ともあれ、printという関数はScript Engineにおいて、標準出力として使用できるみたいいです。
もちろん、普通にJavaScriptを書いて動かせます。関数を動かすなど。

        ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
        ScriptEngine engine = scriptEngineManager.getEngineByName("js");
        try {
            engine.eval("function hello() {print('Hello World!')}");
            Invocable invocable = (Invocable)engine;
            Object obj = invocable.invokeFunction("hello");
        } catch (ScriptException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

        出力 : Hello World!

Invokeしてキャストしてるところがなぁ。。というのはありつつ。
IDEでこの関数を読み取ってくれるなら嬉しいですが、実行時エラーになってしまうのが嫌ではありますね。
引数入れて関数呼ぶのも出来ます。
そして、面白いと思ったのは、変数の引き渡しもできます。

引き渡し

            Integer i = 241;
            engine.put("key",i);
            System.out.println(engine.eval("typeof(key);"));
            System.out.println(engine.eval("key"));

            出力 :
            number
       241

色々対応してるみたいで

js java
Number Double,Integer,Long,....
String String
Boolean Boolean
未定義 Singleton Object
Object Map

↑こんな感じ

まずはJavaからJavascriptを呼び出すことにおいて、基本的なことは一通りできそうです。
色々やれること、勉強することがありそうです。まずはここまで。