Как работает ScriptEngineManager и ScriptEngine?

310
14 октября 2021, 12:50

Какое-то время назад преобразовывал с помощью этих элементов математическое выражение, записанное в виде строки в численный тип, примерно следующим образом: Есть строка str значение которой задаёт пользователь (например cos(x)) и числа a, b, n значение которых тоже задаёт пользователь, программа преобразует строку в другую строку (в данном случае str = str.replaceAll("cos","Math.cos").replaceAll("((x))","(sm)");) Затем происходит следующее:

    ScriptEngineManager engineManager = new ScriptEngineManager(); //что происходит здесь и как это работает?
    ScriptEngine engine = engineManager.getEngineByName("nashorn"); //что происходит здесь, как это работает и почему тип принимаемого значения "nashorn"?
    double h = (b-a)/n;
    double sum = 0;
    double res;
    for (int i=0;i<n;i++){
        a+=h;
        engine.put("sm", a); // что происходит здесь?
        sum += (double) engine.eval(str); // как строка приводится к численному типу, когда она даже не число?
    res = h*sum;

P.S. В полной версии программа рассчитывала значение определённого интеграла по формуле прямоугольника

Answer 1

В Java существует возможность подключать сторонние скриптовые движки. Делается это при помощи ScriptEngineManager через механизм Service Provider. Если говорить простыми словами, ты можешь написать java-приложение, которое будет исполнять, к примеру, Python-код (см пример). Можно подключить и javascript-движок. Одним из таких движков как раз является Nashorn (есть ещё Rhino). Кроме того, он поставляется в стандартном наборе JDK. Более того, в Jdk8 есть даже встроенный web-браузер.

Конкретно по твоему примеру в цикле выполняется javascript код (тут неплохо бы добавить в вопрос реальное содержимое str) наверно содержащий следующее выражение

//var x =...;//значение приходит из Java 
var res=cos(x);
return res;

Но Nashorn не знает о функции cos, в отличии от Firefox или Chrome. Поэтому происходит подмена cos на Math.cos. Плюс идёт подмена имени переменной x на sm, что на мой взгляд кажется сомнительным, можно же просто передавать сразу значение для x при помощи engine.put("x", a);. В итоге получается javascript-код:

//var sm =...;//значение приходит из Java при помощи `engine.put("sm", a);`
var res=Math.cos(sm);
return res;

который и идёт на выполнение в движок Nashorn.

Что касательно кастования к double в

sum += (double) engine.eval(str);

Здесь явно есть проблемы, т.к. согласно сигнатуре метода ScriptEngine#eval возвращается тип Object. Более корректно было бы кастовать к типу Number и потом извлекать примитив при помощи doubleValue примерно так:

sum += ((Number) engine.eval(str)).doubleValue();
READ ALSO
Как сделать из строки численное выражение? [дубликат]

Как сделать из строки численное выражение? [дубликат]

Пишу калькулятор, в который можно вбивать математические выражения любой длины, после чего пользователь нажимает клавишу "=" и калькулятор...

97
Адаптивная верстка DIV [закрыт]

Адаптивная верстка DIV [закрыт]

Хотите улучшить этот вопрос? Обновите вопрос так, чтобы он вписывался в тематику Stack Overflow на русском

228
Большая задержка в вводе текст SFML

Большая задержка в вводе текст SFML

Всем привет, в моём проекте sfml используется ввод текста в текстовое полеПо умолчанию такой функции нет в sfml, но я поискал в интернете и нашёл...

239