Вопрос-ответ

Is there an eval() function in Java?

Есть ли функция eval() в Java?

У меня есть строка, подобная следующей:

String str = "4*5";

Теперь я должен получить результат 20 с помощью строки.

Я знаю, что в некоторых других языках eval() функция сделает это. Как я могу сделать это в Java?

Переведено автоматически
Ответ 1

Вы можете использовать класс ScriptEngine и оценить его как строку Javascript.

ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("js");
Object result = engine.eval("4*5");

Возможно, есть способ получше, но этот работает.

Ответ 2

Не существует стандартного класса или метода Java, который будет делать то, что вы хотите. Ваши варианты включают:


  • Выберите и используйте какую-нибудь стороннюю библиотеку вычисления выражений. Например, JEL или любую из полудюжины библиотек, перечисленных здесь.



  • Оберните выражение в исходный код Java для класса с помощью eval метода, отправьте его компилятору Java, а затем загрузите полученный скомпилированный класс.



  • Используйте какой-нибудь язык сценариев, который может быть вызван из Java в качестве средства вычисления выражений. Возможности включают Javascript1, BeanShell и так далее. Реализация языка сценариев, совместимая с JSR 223, может быть вызвана через Scripting API.



  • Напишите свой собственный вычислитель выражений с нуля.



Первый подход, вероятно, самый простой. Второй и третий подходы представляют потенциальную угрозу безопасности, если вы получаете выражение для вычисления от ненадежного пользователя. (Подумайте о внедрении кода.)


1 - Javascript в Java SE - это движущаяся цель. Начиная с Java 6, версия реализации Rhino Javascript от Mozilla шла в комплекте с Java SE. В Java 8 ее заменил Nashorn. В Java 11 Nashorn устарел и, наконец, был удален из основной кодовой базы. По состоянию на 2021 год Rhino и Nashorn поддерживаются как отдельные (не принадлежащие Oracle) продукты, а GraalVM от Oracle имеет собственную реализацию Javascript.

Ответ 3

Существует очень мало реальных вариантов использования, в которых возможность оценивать String как фрагмент кода Java необходима или желательна. То есть вопрос о том, как это сделать, на самом деле является проблемой XY: на самом деле у вас другая проблема, которую можно решить другим способом.

Сначала спросите себя, откуда взялась эта String функция, которую вы хотите оценить? Ее сгенерировала другая часть вашей программы или она была введена пользователем?


  • Другая часть моей программы сгенерировала ее: итак, вы хотите, чтобы одна часть вашей программы решала, какую операцию выполнять, но не выполняла саму операцию, а вторая часть выполняла выбранную операцию. Вместо генерации и последующей оценки String используйте шаблон проектирования Strategy, Command или Builder, в зависимости от вашего конкретного случая.


  • Это пользовательский ввод: пользователь может вводить что угодно, включая команды, которые при выполнении могут привести к неправильному поведению вашей программы, аварийному завершению работы, раскрытию информации, которая должна быть секретной, повреждению постоянной информации (такой как содержимое базы данных) и другой подобной гадости. Единственный способ предотвратить это - самостоятельно проанализировать String, убедиться, что это не вредоносное по, а затем оценить его. Но разбор ее самостоятельно - это большая часть работы, которую выполнила бы запрошенная evalфункция, поэтому вы ничего не сэкономили. Что еще хуже, проверка того, что arbitrary Java не был вредоносным, невозможна, потому что проверка этого является проблемой остановки.


  • Это пользовательский ввод, но синтаксис и семантика разрешенного для оценки текста сильно ограничены: ни одно средство общего назначения не может легко реализовать анализатор общего назначения и вычислитель для любого выбранного вами ограниченного синтаксиса и семантики. Что вам нужно сделать, так это реализовать анализатор и вычислитель для выбранного вами синтаксиса и семантики. Если задача простая, вы могли бы написать простой рекурсивный спуск или анализатор конечного автомата вручную. Если задача сложная, вы могли бы использовать компилятор-компилятор (такой как ANTLR), чтобы выполнить часть работы за вас.


  • Я просто хочу реализовать настольный калькулятор!: Домашнее задание, да? Если бы вы могли реализовать вычисление входного выражения с помощью предоставленной eval функции, это не было бы большим домашним заданием, не так ли? Ваша программа была бы длиной в три строки. Ваш инструктор, вероятно, ожидает, что вы напишете код для простого арифметического анализатора / вычислителя. Существует хорошо известный алгоритм, shunting-yard, который может оказаться полезным.


Ответ 4

С Java 9 мы получаем доступ к jshell, поэтому можно написать что-то вроде этого:

import jdk.jshell.JShell;
import java.lang.StringBuilder;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;

public class Eval {
public static void main(String[] args) throws IOException {
try(JShell js = JShell.create(); BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) {

js.onSnippetEvent(snip -> {
if (snip.status() == jdk.jshell.Snippet.Status.VALID) {
System.out.println("➜ " + snip.value());
}
});

System.out.print("> ");
for (String line = br.readLine(); line != null; line = br.readLine()) {
js.eval(js.sourceCodeAnalysis().analyzeCompletion(line).source());
System.out.print("> ");
}
}
}
}

Пример запуска:

> 1 + 2 / 4 * 3
1
> 32 * 121
3872
> 4 * 5
20
> 121 * 51
6171
>

Немного оп, но это то, что в настоящее время может предложить Java

java