Почему люди говорят, что Java не может иметь оценщика выражений?
Мне известно, что по умолчанию у Java нет так называемого eval
(то, что я произношу как "злой" ) метод. Это звучит как плохая вещь, зная, что у вас нет того, что делают многие другие. Но еще хуже кажется, что вас не знают, что вы не можете этого сделать.
Мой вопрос: что такое твердое рассуждение? Я имею в виду, что Google просто возвращает огромное количество старых данных и ложных причин. Даже если есть ответ, который я ищу, я не могу отфильтровать его от людей, которые просто бросают общие теги-слова.
Меня не интересуют ответы, которые говорят мне, как обойти это; Я могу сделать это сам:
Использование Bean Scripting Framework (BSF)
Файл sample.py
(в папке py
):
def factorial(n):
return reduce(lambda x, y:x * y, range(1, n + 1))
И код Java:
ScriptEngine engine = new ScriptEngineManager().getEngineByName("jython");
engine.eval(new FileReader("py" + java.io.File.separator + "sample.py"));
System.out.println(engine.eval("factorial(932)"));
Использование сконструированных мостов, таких как JLink
![example]()
Это эквивалентно:
String expr = "N[Integrate[E^(2 y^5)/(2 x^3), {x, 4, 7}, {y, 2, 3}]]";
System.out.println(MM.Eval(expr));
//Output: 1.5187560850359461*^206 + 4.2210685420287355*^190*I
Другие методы
- Использование алгоритма Shynchstras или аналогичного сценария и написания оценщика выражений с нуля.
- Использование сложных регулярных выражений и строковых манипуляций с делегатами и HashMultimaps.
- Использование библиотеки Java Expressions
- Использование языка выражения Java
- Использование JRE-совместимого скриптового языка, такого как BeanShell.
- Использование Java Assembler и подход ниже или прямой манипуляции с байт-кодом, например Javaassist.
- Использование API компилятора Java и отражений.
- Использование
Runtime.getRuntime().exec
как root
Ответы
Ответ 1
"eval" доступен только на языках сценариев, поскольку он использует тот же интерпретатор, который запускает остальную часть кода; на таких языках эта функция бесплатна и хорошо интегрирована, так как в среде сценариев это мало влияет, если вы запускаете строку или "реальную" функцию.
В переписанных языках добавление "eval" означает объединение всего компилятора, что помешало бы цели компиляции. Нет компилируемого языка, который я знаю (даже динамические, такие как ActionScrip3) имеют eval.
Кстати, самый простой способ eval на Java - это тот, который вы забыли упомянуть: JRE 1.6 поставляется с механизмом Javascript, поэтому вы можете оценить любой Javascript в двух строках кода. Вы даже можете утверждать, что предпосылка вашего вопроса ложна. Java 1.6 объединяет очень продвинутый оценщик выражений.
Ответ 2
Как указывает Дэниел, есть хотя бы одно ограничение, которое eval-solutions стоят в java. Например, php eval выполняет код так, как если бы он был частью окружающего метода с полным доступом к локальным переменным, это невозможно сделать в стандартной java. Без этой возможности альтернативные альтернативы требуют гораздо больше работы и многословия, что делает их намного менее привлекательными для "быстрых" и "простых" решений.
eval()
в основном является частью интерпретируемых языков, где имена локальных переменных и структуры кода (области) доступны во время выполнения, что позволяет "вставить" новый код. Байт-код Java больше не содержит эту информацию, оставляя альтернативы eval() неспособными сопоставить доступ к локальным переменным. (Примечание: я игнорирую отладочную информацию, поскольку никакая программа не должна полагаться на нее, и она может отсутствовать)
Пример
int i = 0;
eval("i = 1");
System.out.println(i);
требуется псевдокод для java
context.put("i",new Integer(0));
eval(context,"i = 1");
System.out.println(context.get("i"));
Это выглядит хорошо для одной переменной, используемой в eval, попробуйте ее на 10 в более длинном методе, и вы получите 20 дополнительных строк для доступа к переменной и той или иной ошибки времени выполнения, если вы ее забудете.
Ответ 3
Поскольку оценка произвольных выражений Java зависит от контекста, переменных областей и т.д.
Если вам нужно какое-то переменное выражение, просто используйте структуру сценариев и badamm! у вас много разных выражений. Просто возьмите один вид, как JavaScript по умолчанию, и есть ваш eval()!
Предпринимательство как Java, вы не ограничены одним выбором.
Ответ 4
Но еще хуже кажется, что вас не знают, что вы не можете его получить.
Я думаю, вы неправильно понимаете, что (в большинстве) эти статьи говорят. Очевидно, что существует множество способов оценки выражений в приложении Java. Они не всегда были доступны, но по крайней мере некоторые из них были в течение долгого времени.
Я думаю, что люди пытаются сказать, что оценка выражения недоступна как родная (т.е. как неотъемлемая часть Java или стандартных библиотек) и вряд ли будет добавлена по ряду веских причин. Например:
- Нативный eval будет иметь серьезные проблемы с безопасностью при неправильном использовании. (И это относится к другим языкам, например, вы не должны использовать
eval
в Javascript для чтения JSON, потому что это может быть путь для ввода плохих вещей в пользовательский браузер.)
- Нативный eval будет иметь значительные проблемы с производительностью по сравнению с скомпилированным кодом Java. Мы говорим о 100 - 10 000 раз медленнее, в зависимости от методов реализации и количества кеширования "скомпилированных" выражений eval.
- Нативный eval представит целый набор проблем надежности... так же, как чрезмерное использование/неправильное использование литья и отражения типов.
- Native eval - это не Java. Java - это, прежде всего, статический язык программирования.
и, конечно...
- Существуют и другие способы сделать это, включая все подходы к реализации, которые вы указали. Платформа Java SE не занимается предоставлением каждой возможной библиотеки, которую любой может захотеть. (Загрузка JRE уже достаточно велик.)
По этим причинам и, возможно, и другим, разработчики языка Java решили не поддерживать оценку выражения изначально в Java SE. (Несмотря на это, поддержка некоторых выражений официально превратилась в Java EE, например, в виде языка выражения JSP. Классы находятся в пакете javax.el
... или javax.servlet.jsp.el
для более старой/устаревшей версии.)
Ответ 5
Я думаю, что вы уже положили решение на свой ответ - объедините банку BeanShell с вашим приложением (или лобби, чтобы он был включен в JRE когда-нибудь), и у вас есть оценщик выражения Java. Тем не менее, для этого потребуется привязка входных переменных.
(Что мне больше любопытно: как работает песочница такого выражения script/Я не хочу, чтобы мои веб-пользователи выполняли опасный код на моем сервере.)