1
function increment(in) ++in
条件捕获语句
可以添加仅在指定条件为真时执行的特定 catch 子句:
1
2
3
4
5
6
7
try {
throw "BOOM";
} catch(e if typeof e === 'string') {
print("String thrown: " + e);
} catch(e) {
print("this shouldn't happen!");
}
使用 来设置对象原型。
定义了一个 API 扩展,使我们能够更改对象的原型:
1
Object.setPrototypeOf(obj, newProto);
该函数通常被认为是 .. 的更好选择,因为它应该是在所有代码中设置对象原型的首选方法。
表达式和数据流
每个人都喜欢并直播——也! 虽然 5.1 没有 Java8 表达式的简化箭头语法,但我们可以在任何接受表达式的地方使用函数文字。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var list = new java.util.ArrayList();
list.add("a1");
list.add("a2");
list.add("a3");
list.add("b1");
list.add("b2");
list.add("b3");
list.add("c1");
list.add("c2");
list.add("c3");
list
.stream()
.filter(function(el) {
return el.startsWith("a");
})
.sorted()
.forEach(function(el) {
print(el);
});
// a1, a2, a3
类继承
Java类型可以很容易地被Java继承。 您甚至可以在脚本中创建多线程代码,如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var Runnable = Java.type('java.lang.Runnable');
var Printer = Java.extend(Runnable, {
run: function() {
print('printed from a separate thread');
}
});
var Thread = Java.type('java.lang.Thread');
new Thread(new Printer()).start();
new Thread(function() {
print('printed from another thread');
}).start();
// printed from a separate thread
// printed from another thread
函数重载
方法和函数可以使用点或括号运算符调用:
1
2
3
4
var System = Java.type('java.lang.System');
System.out.println(10); // 10
System.out["println"](11.0); // 11.0
System.out["println(double)"](12); // 12.0
当调用重载参数的方法时,传递可选参数 type() 指定被调用的具体方法。
爪哇豆
您可以简单地使用属性名称来获取或设置 Java Bean 的值,而无需显式调用 或 :
1
2
3
4
var Date = Java.type('java.util.Date');
var date = new Date();
date.year += 1900;
print(date.year); // 3918
属性绑定
两个不同对象的属性可以绑定在一起:
1
2
3
4
5
6
7
8
var o1 = {};
var o2 = { foo: 'bar'};
Object.bindProperties(o1, o2);
print(o1.foo); // bar
o1.foo = 'rab';
print(o2.foo); // rab
字符串扩展
原型上提供了两个简单但非常有用的扩展。 这些是求和函数,它们返回删除了空格的副本:
1
2
print(" hello world".trimLeft());
print("hello world ".trimRight());
地点
通过全局变量可以获取当前的文件名、目录和行,并且:
1
print(__FILE__, __LINE__, __DIR__);
进口范围
有时一次导入多个 Java 包很方便。 我们可以将类与 with 语句一起使用。 导入包的所有类文件都可以在 with 语句的本地范围内访问。
1
2
3
4
5
var imports = new Javaimporter(java.io, java.lang);
with (imports) {
var file = new File(__FILE__);
System.out.println(file.getAbsolutePath());
}
数组转换
以下代码将 Java List 转换为本机数组:
1
2
3
4
5
6
7
var javaList = new java.util.ArrayList();
javaList.add("1");
javaList.add("2");
javaList.add("3");
var jsArray = Java.from(javaList);
print(jsArray); // 1, 2, 3
print(Object.prototype.toString.call(jsArray)); // [object Array]
以下代码执行相反的操作:
1
var javaArray = Java.to([3, 5, 7, 11], "int[]");
访问超类
通常很难访问 中的重写成员,因为 中不存在 Java 的 super 关键字。 幸运的是,有一套补救措施。
首先我们需要在Java代码中定义超类:
1
2
3
4
5
6
class SuperRunner implements Runnable {
@Override
public void run() {
System.out.println("super run");
}
}
下面我已经介绍了。 创建新实例时要注意语法:重写成员的语法取自Java的匿名对象。
1
2
3
4
5
6
7
8
9
10
11
12
13
var SuperRunner = Java.type('my.package.SuperRunner');
var Runner = Java.extend(SuperRunner);
var runner = new Runner() {
run: function() {
Java.super(runner).run();
print('my run');
}
}
runner.run();
// super run
// my run
我们通过 Java.super() 扩展调用了重写的 .run() 方法。
神奇和
可以在对象上定义方法,每当访问未定义的属性或调用未定义的方法时都会调用这些方法:
1
2
3
4
5
6
7
8
9
10
11
12
var demo = {
__noSuchProperty__: function (propName) {
print("Accessed non-existing property: " + propName);
},
__noSuchMethod__: function (methodName) {
print("Invoked non-existing method: " + methodName);
}
};
demo.doesNotExist;
demo.callNonExistingMethod()
这将输出:
1
2
Accessed non-existing property: doesNotExist
Invoked non-existing method: callNonExistingMethod
java.
使用这个函数,我们可以获得一个与Java JSON库的期望兼容的对象。 代码如下所示:
1
2
3
4
5
6
7
Object obj = engine.eval("Java.asJSonCompatible(
{ number: 42, greet: 'hello', primes: [2,3,5,7,11,13] })");
Mapmap = (Map )obj;
System.out.println(map.get("greet"));
System.out.println(map.get("primes"));
System.out.println(List.class.isAssignableFrom(map.get("primes").getClass()));
这将输出:
1
2
hello
[2, 3, 5, 7, 11, 13]
加载脚本
您可以在脚本引擎中加载其他文件:
1
load('classpath:script.js');
或者通过 URL 加载脚本:
1
load('/script.js');
请记住,没有名称空间的概念,因此所有内容都堆积到全局环境中。 这使得加载的脚本可能与您的代码或它们之间存在命名冲突。 这可以通过使用以下函数来最小化:
1
2
var math = loadWithNewGlobal('classpath:math_module.js')
math.increment(5);
.js文件内容如下:
1
2
3
4
5
6
7
var math = {
increment: function(num) {
return ++num;
}
};
math;
这里我们定义了一个名为 math 的对象,并在其中调用了一个函数。 使用这种范例,我们可以实现基本的模块化。
将本机对象传递给 Java 时,您使用类,它们实际上是底层对象的 Java 表示。 实现Map接口,位于jdk..api中。 该包中的类可以在 Java 代码中使用。
下面的例子将参数类型从 改为 ,我们可以从传入的对象中获取一些信息。
1
2
3
4
static void fun(scriptObjectMirror mirror) {
System.out.println(mirror.getClassName() + ": " +
Arrays.toString(mirror.getOwnKeys(true)));
}
当将对象(哈希表)传递给此方法时,可以在 Java 中访问其属性:
1
2
3
4
5
6
MyJavaClass.fun({
foo: 'bar',
bar: 'foo'
});
// Object: [foo, bar]
我们还可以调用Java中的函数。 让我们首先定义一个具有属性和函数的类型。
1
2
3
4
5
6
7
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
this.getFullName = function() {
return this.firstName + " " + this.lastName;
}
}
方法可以通过() 来调用。
1
2
3
static void fun(scriptObjectMirror person) {
System.out.println("Full Name is: " + person.callMember("getFullName"));
}
当将 new 传递给 Java 方法时,我们会在控制台上看到预期的输出:
1
2
3
4
var person = new Person("Peter", "Parker");
MyJavaClass.fun(person);
// Full Name is: Peter Parker
限制脚本访问特定 Java 类
jdk..api..接口通过运行脚本来限制对特定Java类的访问,提供对Java类的代码访问的细粒度控制。 示例代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import javax.script.scriptEngine;
import jdk.nashorn.api.scripting.ClassFilter;
import jdk.nashorn.api.scripting.NashornscriptEngineFactory;
public class MyClassFilterTest {
class MyCF implements ClassFilter { // 创建类过滤器
@Override
public boolean exposeToscripts(String s) {
if (s.equals("java.io.File")) {
return false;
}
return true;
}
}
public void testClassFilter() {
final String script =
"print(java.lang.System.getProperty(\"java.home\"));" +
"print(\"Create file variable\");" +
"var File = Java.type(\"java.io.File\");";
NashornscriptEngineFactory factory = new NashornscriptEngineFactory();
scriptEngine engine = factory.getscriptEngine(new MyClassFilterTest.MyCF());
try {
engine.eval(script);
} catch (Exception e) {
System.out.println("Exception caught: " + e.toString());
}
}
public static void main(String[] args) {
MyClassFilterTest myApp = new MyClassFilterTest();
myApp.testClassFilter();
}
最终这会引发 java.lang.on 异常。
命令行脚本
如果您对编写命令行(shell)脚本感兴趣,请尝试一下 Nake。 Nake 是 Java 8 的简化构建工具。您只需在特定于项目的任务中定义任务,然后通过在命令行中键入 bare -- 来执行它们。 任务以脚本模式编写和运行,因此您可以使用终端、JDK8 API 和任意 Java 库的全部功能。
对于 Java 开发人员来说,编写命令行脚本从未如此简单......
本文部分内容来自: