Java 8 Nashorn 引擎

原创
2014/03/25 17:00
阅读数 1.7W

Java 8 Nashorn 脚本引擎

java8 终于来了.函数式接口,lambda表达式期待很久了.新的武器在手,应该可以玩出新花样.

前两天无意中发现java8 中还带了另外一个有意思的东西.

Nashorn 一个javascript引擎.

这等好玩的东西不把玩一下实在是浪费了.所以直接找到了oracle官方的介绍文档.说实话,文档真给力啊.

这篇文章是我一边看Oracle官方文档,一边敲代码试验,一边写的,不算是翻译的文档,算是中文版总结文档吧.呵呵.

#原文地址:Oracle Nashorn: A Next-Generation JavaScript Engine for the JVM

java7以前,JDK内置了一个基于Mozilla Rhino的javascript脚本引擎.在java8里面,基于JSR292和invokedynamic重新提供了一个新的javascript引擎-Oracle Nashorn.它更符合ECMA标准的javascript规范,而且基于invokedynamic调用拥有更好的性能.

文章使用的是最新的JDK8.所以想用要先装一下.

  • 第一个栗子

    第一个程序一定是HelloWorld.而且是命令行下面的实现.因此.打开一个命令行吧.

    如果你的命令行配好了,输入 jjs 回车

    就可以看到Nashrn的命令行了.

    print("hello halu");

    如果你人品没问题,你一定看到输出了...../抠鼻

  • 第二个栗子

    命令行下面可以用了,那么抓紧试试用js文件吧.

    把下面的代码保存在一个文件里面,我的文件名是halu.js

      function SayHi(){
          print("hello halu");
       }
       SayHi();
    

    然后打开命令行,cd到文件所在的目录.

windows下面cd有个技巧可以用.在文件夹空白的位置按住shift右击鼠标,菜单中会出现在此处打开命令窗口的选项,一般人我可不告诉他.

命令行下输入 jjs halu.js 就可以看到执行结果了.

  • 第三个栗子

    要知道,这可是java8 环境.看下面的例子吧.

      var data = [1,2,3,4,5,6,7,8,9,10];
      var filtered = data.filter(function(i){
           return i%2 == 0;
      },0);
      print(filtered);
      var sumOfFilterd = filtered.reduce(function (acc,next){
      return acc + next;
          },0);
      print(sumOfFilterd);
    

看一下执行结果吧.这个例子里面信息量可是巨大的.

Nashorn 只是使用遵从 ECMA 规范的javascript语言,在网页上常用的对象Nashorn里面并没有.比如说 console,window等对象.

  • 第四个栗子

命令行执行以下 jjs -help,在帮助中可以看到.

  • jjs可以运行javaFX程序脚本
  • 可以使用javascript严格模式.
  • 可以指定额外的classpath.
  • 一个有趣的脚本模式

脚本模式很有趣,你可以使用jjs运行使用javascript编写的系统脚本.类似python,ruby,bash脚本.脚本模式有两种扩展:heredocsshell invocations.

 var data = {
      foo:"bar",
      time: new Date()
 };
 print("< So...foo = ${data.foo} and the current time is ${data.time} EOF");

使用 jjs -scripting halu.js 执行该脚本.

heredocs 是一种简单的多行文本,使用类似bash的语法.使用 < 符号开始后面跟一个特殊标记.字符串中可以使用 ${} 表达式(类似EL表达式).需要注意的是,如果使用单引号引起来的字符串,内部的标示是不会被替换的.

  • 第五个栗子

Shell invocations 是允许调用命令行程序.

 var lines =\`ls`;
 print(lines);

这样就可以执行shell命令了.当然windows下面失败....

**注意符号是 ` [波浪线那个键],不是 ' [单引号] ** ,我找了好久才发现.

  • 第六个栗子

下面我们来写一个 java 程序

 import javax.script.ScriptEngine;
 import javax.script.ScriptEngineManager;
 public class halu{
     public static void main(String[] args) throws Throwable{
         ScriptEngineManager engineManager = new ScriptEngineManager();
         ScriptEngine engine = engineManager.getEngineByName("nashorn");
         engine.eval("function sum(a,b){return a+b;}");
         System.out.println(engine.eval("sum(1,2);"));
     }
 }

这段代码很简单,使用ScriptEngineManager 获得一个 ScriptEngine.然后通过eval函数执行字符串脚本.

 Invocable invocable = (Invocable) engine;
 System.out.println(invocable.invokeFunction("sum",1,3));

engine 也可以使用invocable接口调用脚本内的函数.

增加一个 Adder.java 的接口

 public interface Adder{
     int sum(int a, int b);
 }

halu类里面

 Adder adderaa = invocable.getInterface(Adder.class);
 System.out.println(""+ adderaa.sum(2,3));

这样可以将javascript的类映射到java的接口上.个人感觉这是个很强大的功能.

读取脚本文件执行.使用 java.io.FileReader;

 engine.eval(new FileReader("halu.js"));
  • 第七个栗子

我们来使用javascript调用java

  print(java.lang.System.currentTimeMillis());
  var file = new java.io.File("halu.js");
  print(file.getAbsolutePath());
  print(file.absolutePath);

使用 jjs 命令执行哦~

集合的使用

 var stack =
 new java.util.LinkedList();
 [1, 2, 3, 4].forEach(function(item) {
      stack.push(item);
 });
 print(stack);
 print(stack.getClass());
  • 第八个栗子

javascript实现java接口

 var iterator = new java.util.Iterator({
     i: 0,
     hasNext: function() {
         return this.i < 10;
     },
     next: function() {
         return this.i++;
     }
 });
 print(iterator instanceof Java.type("java.util.Iterator"));
 while (iterator.hasNext()) {
     print("-> " + iterator.next());
 }
  • 第九个栗子

javascript 实现多个接口

var ObjectType = Java.type("java.lang.Object");
var Comparable = Java.type("java.lang.Comparable");
var Serializable = Java.type("java.io.Serializable");
var MyExtender = Java.extend(
    ObjectType, Comparable, Serializable);
var instance = new MyExtender({
    someInt: 0,
    compareTo: function(other) {
        var value = other["someInt"];
        if (value === undefined) {
            return 1;
        }
        if (this.someInt < value) {
            return -1;
        } else if (this.someInt == value) {
            return 0;
        } else {
            return 1;
        }
    }
});
print(instance instanceof Comparable);
print(instance instanceof Serializable);
print(instance.compareTo({ someInt: 10 }));
print(instance.compareTo({ someInt: 0 }));
print(instance.compareTo({ someInt: -10 }));

终于完了....累死我了....

感受

Nashorn 真心好玩.javascript语言本身就有无限可能性,应该能做出来一些好玩的东西.下面就该考虑如何使用Nashorn做点东西了.

#PS: shell invocable 不支持 windows 真心觉得坑.....谁要是有办法请留言给我.

展开阅读全文
打赏
30
155 收藏
分享
加载中
架构梦想博主

引用来自“Crazy__long”的评论

win7, var lines =\`ls`; 改成 var lines =`ls`; 在gitbash 环境可以运行成功。

回复@Crazy__long : 谢谢
2017/04/11 16:47
回复
举报
win7, var lines =\`ls`; 改成 var lines =`ls`; 在gitbash 环境可以运行成功。
2017/04/11 10:59
回复
举报
这样可以用js给java写测试了, 不过目前用的spock.
2016/06/15 09:21
回复
举报
@架构梦想 先有这想法的是Beetl,但是我们有分歧,我更希望做成更像“脚本”的模版引擎
2014/03/26 20:52
回复
举报
架构梦想博主

引用来自“webit”的评论

哈哈, mark,我的 Webit Script 可以参考一下

javascript 语法的前端模板???

这想法太棒了.....
2014/03/26 20:13
回复
举报
架构梦想博主

引用来自“19岁的天空”的评论

说实话,不看好这东西~~

只是说JAVA8给我们提供了一种可能性,未来扩展怎么样的应用才是我们考虑的.
就目前来看原生的jdk没有脚本支持有些动态的功能真的不好实现.只能辗转groovy或者scala去处理.十分不顺手.
2014/03/26 20:11
回复
举报
架构梦想博主

引用来自“撸蕉香的程猿序”的评论

引用来自“hantsy”的评论

引用来自“架构梦想”的评论

引用来自“吐槽的达达仔”的评论

这。。是java还是JavaScript啊?

oracle java8 里面内置的javascript引擎~

Java 8 中 JavaScript 可以调用 JAVA API,这个才是诱人的地方 。。。Oracle 也在推出一个 Avatar (Glassfish网站可以找到)的服务器 JS 项目(与 NODE 竞争),同时 Java EE 8 的调查中显示,Oracle 可能会加入服务器端 JS Event的标准。

做技术真累。

scala clojure groovy 和java都可以混编。都没火起来。再加一个js也没戏

这些语言不是要取代JAVA,而是完成java不容易实现的地方.
Play框架的快速.
clojure的并行
groovy的灵活.
都是为了弥补java在某些特性下的薄弱.
JVM平台竞争的时代已经来临了.
2014/03/26 20:09
回复
举报
说实话,不看好这东西~~
2014/03/26 19:02
回复
举报

引用来自“hantsy”的评论

引用来自“架构梦想”的评论

引用来自“吐槽的达达仔”的评论

这。。是java还是JavaScript啊?

oracle java8 里面内置的javascript引擎~

Java 8 中 JavaScript 可以调用 JAVA API,这个才是诱人的地方 。。。Oracle 也在推出一个 Avatar (Glassfish网站可以找到)的服务器 JS 项目(与 NODE 竞争),同时 Java EE 8 的调查中显示,Oracle 可能会加入服务器端 JS Event的标准。

做技术真累。

scala clojure groovy 和java都可以混编。都没火起来。再加一个js也没戏
2014/03/26 18:30
回复
举报
该评论暂时无法显示,详情咨询 QQ 群:912889742
更多评论
打赏
33 评论
155 收藏
30
分享
返回顶部
顶部