Почему люди говорят, что в Java не может быть оценщика выражений? - PullRequest
11 голосов
/ 12 марта 2011

Мне известно, что по умолчанию в 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

Другие методы

  • Использование алгоритма Dijkstras shunting-yard или аналогичного и написание оценщика выражений с нуля.
  • Использование сложных регулярных выражений и операций со строками с делегатами и HashMultimaps.
  • Использование библиотеки выражений Java
  • Использование языка выражений Java
  • Использование JRE-совместимого языка сценариев, такого как BeanShell.
  • Использование Java Assembler и подход ниже или прямое манипулирование байт-кодом, как Javaassist.
  • Использование API компилятора Java и отражений.
  • Использование Runtime.getRuntime().exec в качестве root

Ответы [ 5 ]

6 голосов
/ 13 марта 2011

«eval» доступен только на языках сценариев, потому что он использует тот же интерпретатор, который выполняет остальную часть кода; в таких языках эта функция бесплатна и хорошо интегрирована, поскольку в среде сценариев не имеет значения, запускаете ли вы строку или «настоящую» функцию.

В копируемых языках добавление «eval» означало бы объединение всего компилятора, что не соответствовало бы цели компиляции. Я не знаю ни одного скомпилированного языка (даже динамического, например ActionScrip3).

Кстати, самый простой способ оценки в Java - это тот, который вы забыли упомянуть: JRE 1.6 поставляется с движком Javascript, так что вы можете проверить любой Javascript в две строки кода. Вы можете даже утверждать, что предположение вашего вопроса неверно. Java 1.6 объединяет очень продвинутый оценщик выражений .

5 голосов
/ 13 марта 2011

Как указывает Даниэль, есть как минимум одно ограничение, с которым сталкиваются eval-решения в Java. Например, php eval выполняет код, как если бы он был частью окружающего метода с полным доступом к локальным переменным, это невозможно сделать в стандартном java. Без этой функции альтернативы eval требуют гораздо больше работы и многословия, что делает их намного менее привлекательными для «быстрых» и «простых» решений.

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 дополнительных строк для доступа к переменной и ту или иную ошибку времени выполнения, если вы забудете одну.

2 голосов
/ 13 марта 2011

Но еще хуже, кажется, уведомление о том, что вы не можете получить его.

Я думаю, что вы неправильно понимаете что (большинство) из этих статей говорят. Ясно, что существует много способов оценки выражений в приложении Java. Они не всегда были доступны, но, по крайней мере, некоторые из них были в течение долгого времени.

Я думаю, что люди пытаются сказать, что оценка выражений не доступна как нативная (т.е. как внутренняя часть Java или стандартных библиотек) и вряд ли будет добавлена ​​ для ряда хороших причины. Например:

  • У нативного eval могут быть серьезные проблемы с безопасностью, если он используется не в том месте. (И для других языков; например, вы не должны использовать eval в Javascript для чтения JSON, потому что это может быть путь для вставки плохих вещей в браузер пользователя.)
  • У нативного eval могут быть значительные проблемы с производительностью по сравнению со скомпилированным кодом Java. Мы говорим о 100–10000 раз медленнее, в зависимости от методов реализации и объема кэширования «скомпилированных» выражений eval.
  • Собственный eval привел бы к целому ряду проблем с надежностью ... во многом как чрезмерное / неправильное использование приведения типов и отражения к ним.
  • Родной eval - это не Java. Java спроектирован в основном как статический язык программирования.

и конечно ...

  • Есть и другие способы сделать это, включая все подходы к реализации, которые вы перечислили. Платформа Java SE не занимается предоставлением всех возможных библиотек, которые кто-либо может захотеть. (Загрузки JRE уже достаточно велики.)

По этим и, возможно, по другим причинам разработчики языка Java решили не поддерживать оценку выражений изначально в Java SE. (Несмотря на это, некоторая поддержка выражений официально включена в Java EE; например, в форме языка выражений JSP. Классы находятся в пакете javax.el ... или javax.servlet.jsp.el для более старой / устаревшей версии.)

2 голосов
/ 12 марта 2011

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

Если вам нужно какое-либо выражение переменных, просто используйте среду сценариев и badamm!у вас есть много разных видов оценки выражений.Просто возьмите один вид, такой как JavaScript, по умолчанию, и вы получите eval ()!

Предприимчивость, как и Java, не ограничивается одним выбором.

0 голосов
/ 13 марта 2011

Я думаю, что вы уже нашли решение для своего ответа - поставьте Jar-пакет BeanShell вместе с вашим приложением (или лоббируйте, чтобы он был когда-нибудь включен в JRE), и у вас есть средство оценки выражений Java.Тем не менее, он все еще будет нуждаться в связывании входных переменных.

(Что мне более любопытно: как работает песочница такого сценария / выражения? Я не хочу, чтобы мои веб-пользователи выполняли опаснокод на моем сервере.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...