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