访问未定义的值后 Nashorn 中的输出不一致
Inconsistent output in Nashorn after accessing undefined value
我正在尝试使用 Nashorn 创建 Java 程序的控制台界面。所以我想根据一些默认导入来评估一些输入。问题是当它访问一个未定义的值时。理想情况下,engine.eval
应该抛出 ReferenceError
或 return null
,但我稍后会得到不一致的值:
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
public class Main {
public static void main(String[] args) throws Exception {
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
System.out.println(engine.eval("with(JavaImporter(java.util)) { x }"));
System.out.println(engine.eval("with(JavaImporter(java.util)) { x = 1 }"));
System.out.println(engine.eval("with(JavaImporter(java.util)) { x }"));
}
}
ideone 和 Windows Oracle JDK 1.8.0_101 的结果是:
null
1
null
最后的输出是 null
,但添加 x == null
给出 false。
如果我在第一个字符串中添加任何空格,我会得到这个输出:
null
1
1
如果第一个和最后一个 engine.eval
参数完全相同,包括空格,那么最后一个值似乎是 null
。
x
的值可以在 null
和 1
之间返回,因此它看起来像是引擎中的某种缓存:
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
public class Main {
public static void main(String[] args) throws Exception {
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
System.out.println(engine.eval("with(JavaImporter(java.util)) { x }"));
System.out.println(engine.eval("with(JavaImporter(java.util)) { x = 1 }"));
System.out.println(engine.eval("with(JavaImporter(java.util)) { x }"));
System.out.println(engine.eval("with(JavaImporter(java.util)) { x }"));
System.out.println(engine.eval("with(JavaImporter(java.util)) { x + x }"));
System.out.println(engine.eval("with(JavaImporter(java.util)) { x }"));
}
}
给出:
null
1
null
1
2.0
null
有什么方法可以使它始终如一地给出 null, 1, 1
结果吗?
强制引擎确认变量声明。
只需在第一个脚本中使用 var x
。
System.out.println(engine.eval("with(JavaImporter(java.util)) { var x }"));
System.out.println(engine.eval("with(JavaImporter(java.util)) { x = 1 }"));
System.out.println(engine.eval("with(JavaImporter(java.util)) { x }"));
引擎中有一个 class 缓存,可以通过以下方式创建它来禁用它:
NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
ScriptEngine engine = factory.getScriptEngine(new String[] { "--class-cache-size = 0" });
通过强制重新编译每个表达式,似乎可以解决问题。看起来相同的表达式会根据范围内的变量进行不同的编译。
我正在尝试使用 Nashorn 创建 Java 程序的控制台界面。所以我想根据一些默认导入来评估一些输入。问题是当它访问一个未定义的值时。理想情况下,engine.eval
应该抛出 ReferenceError
或 return null
,但我稍后会得到不一致的值:
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
public class Main {
public static void main(String[] args) throws Exception {
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
System.out.println(engine.eval("with(JavaImporter(java.util)) { x }"));
System.out.println(engine.eval("with(JavaImporter(java.util)) { x = 1 }"));
System.out.println(engine.eval("with(JavaImporter(java.util)) { x }"));
}
}
ideone 和 Windows Oracle JDK 1.8.0_101 的结果是:
null
1
null
最后的输出是 null
,但添加 x == null
给出 false。
如果我在第一个字符串中添加任何空格,我会得到这个输出:
null
1
1
如果第一个和最后一个 engine.eval
参数完全相同,包括空格,那么最后一个值似乎是 null
。
x
的值可以在 null
和 1
之间返回,因此它看起来像是引擎中的某种缓存:
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
public class Main {
public static void main(String[] args) throws Exception {
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
System.out.println(engine.eval("with(JavaImporter(java.util)) { x }"));
System.out.println(engine.eval("with(JavaImporter(java.util)) { x = 1 }"));
System.out.println(engine.eval("with(JavaImporter(java.util)) { x }"));
System.out.println(engine.eval("with(JavaImporter(java.util)) { x }"));
System.out.println(engine.eval("with(JavaImporter(java.util)) { x + x }"));
System.out.println(engine.eval("with(JavaImporter(java.util)) { x }"));
}
}
给出:
null
1
null
1
2.0
null
有什么方法可以使它始终如一地给出 null, 1, 1
结果吗?
强制引擎确认变量声明。
只需在第一个脚本中使用 var x
。
System.out.println(engine.eval("with(JavaImporter(java.util)) { var x }"));
System.out.println(engine.eval("with(JavaImporter(java.util)) { x = 1 }"));
System.out.println(engine.eval("with(JavaImporter(java.util)) { x }"));
引擎中有一个 class 缓存,可以通过以下方式创建它来禁用它:
NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
ScriptEngine engine = factory.getScriptEngine(new String[] { "--class-cache-size = 0" });
通过强制重新编译每个表达式,似乎可以解决问题。看起来相同的表达式会根据范围内的变量进行不同的编译。