Java 8 Nashorn 脚本引擎
java8 终于来了.函数式接口,lambda表达式期待很久了.新的武器在手,应该可以玩出新花样.
前两天无意中发现java8 中还带了另外一个有意思的东西.
Nashorn 一个javascript引擎.
这等好玩的东西不把玩一下实在是浪费了.所以直接找到了Oracle官方的介绍文档.说实话,文档真给力啊.
这篇文章是我一边看Oracle官方文档,一边敲代码试验,一边写的,不算是翻译的文档,算是中文版总结文档吧.呵呵.
原文地址:Oracle Nashorn: A Next-Generation JavaScript Engine for the JVMjava7以前,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脚本.脚本模式有两种扩展:heredocs和shell 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 }));
终于完了….累死我了…. 感受