java - 为什么 eval 类给我一个从 int 到 double 的转换错误?

标签 java function eval scriptmanager integral

我正在尝试创建一种方法,该方法采用字符串公式,并通过以非常小的间隔进行黎曼求和来求解该公式的积分。我使用 ScriptEngine 和 ScriptEngineManager 类来评估函数(使用 eval() 方法)。由于某种原因,我收到此错误:

Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Double at sum.integral(sum.java:31) at sum.main(sum.java:13)

import java.beans.Expression;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

public class sum {

    //testing method
    public static void main(String[] args) throws ScriptException {

        double x = integral("5*x^2",0,5);
        System.out.println(x);

    }

    public static double integral(String function, double lower, double upper) throws ScriptException
    {
        double total = 0;

        ScriptEngineManager mgr = new ScriptEngineManager();
        ScriptEngine engine = mgr.getEngineByName("JavaScript");

        //Solves function from upper to lower with a .001 interval, adding it to the total.
        for (double i = lower; i < upper; i+=.001)
        {
            //evaluates the interval
            engine.put("x",i);
            total += (double)engine.eval(function);
        }

        return total;
    }

}

最佳答案

Nashorn 使用 optimistic typing (自 JDK 8u40 起),因此当不需要 double 时它将使用整数。因此,您不能指望它返回 Double。

此外,5*x^2 在 JavaScript 中表示“五次 x x 或两次”。 ** 指数运算符是在较新版本的 JavaScript 语言中定义的,但 Nashorn 尚不支持它。

如果您将 JavaScript 代码更改为 5*x*x 它将起作用,但这样做会更安全:

total += 0.001 * ((Number)engine.eval(function)).doubleValue();

编译常用代码

由于您在循环中重复调用此函数,因此最佳实践是提前编译该函数。这种性能优化并不是绝对必要的,但因为引擎每次都必须编译您的函数(尽管它可能使用缓存来帮助实现这一点)。

import javax.script.Compilable;
import javax.script.CompiledScript;
import javax.script.Invocable;
import javax.script.ScriptContext;

CompiledScript compiledScript = ((Compilable)engine)
    .compile("function func(x) { return " + function + "}");
compiledScript.eval(compiledScript.getEngine()
    .getBindings(ScriptContext.ENGINE_SCOPE));

Invocable funcEngine = (Invocable) compiledScript.getEngine();

// . . .

total += 0.001 * ((Number)funcEngine.invokeFunction("func", i)).doubleValue();

使用 ES6 语言功能

将来,当 Nashorn 支持 ** 运算符时,如果你想使用它,你可能需要像这样开启 ES6 功能:

import jdk.nashorn.api.scripting.NashornScriptEngineFactory;

NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
ScriptEngine enjin = factory.getScriptEngine("--language=es6");

或者像这样:

java -Dnashorn.args=--language=es6

* 进行编辑以说明评论中指出的数学修正。

关于java - 为什么 eval 类给我一个从 int 到 double 的转换错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44251284/

相关文章:

java - 从 Assets 中打开 pdf

java - 组织 AsyncTask 的最佳方式

java - 如果我使用 swapoff -a 关闭交换并使用 RandomAccessFile 写入一些数据,它会每次刷新到磁盘吗?

function - scala foreach 和 map 初始化器

javascript - JQuery getJSON - ajax 解析错误

java - jax-ws: "keep"工具中的 "wsgen"标志究竟有什么作用?

node.js - 如何轻松包装整个 (Redis) 客户端

javascript - JavaScript 中的默认函数参数

python - 带参数的eval函数

python - 如何从 Python 中的被调用模块访问调用模块命名空间?