«1. Обзор

В этом руководстве мы обсудим различные подходы к вычислению математического выражения с помощью Java. Эта функция может пригодиться в проектах, где мы хотим оценить математические выражения, представленные в строковом формате.

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

2. exp4j

exp4j — это библиотека с открытым исходным кодом, которую можно использовать для вычисления математических выражений и функций. Библиотека реализует алгоритм Дейкстры Shunting Yard Algorithm, метод разбора математических выражений, заданных в инфиксной нотации.

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

2.1. Добавление зависимости Maven

Чтобы использовать exp4j, нам нужно добавить зависимость Maven в наш проект:

<dependency>
    <groupId>net.objecthunter</groupId>
    <artifactId>exp4j</artifactId>
    <version>0.4.8</version>
</dependency>

2.2. Вычисление простых выражений

Мы можем оценить простое математическое выражение, представленное в формате String:

@Test
public void givenSimpleExpression_whenCallEvaluateMethod_thenSuccess() {
    Expression expression = new ExpressionBuilder("3+2").build();
    double result = expression.evaluate();
    Assertions.assertEquals(5, result);
}

В приведенном выше фрагменте кода мы сначала создаем экземпляр ExpressionBuilder. Затем мы назначаем его ссылке Expression, которую мы используем для оценки нашего выражения.

2.3. Использование переменных в выражениях

Теперь, когда мы знаем, как вычислять простые выражения, давайте добавим в наше выражение несколько переменных:

@Test
public void givenTwoVariables_whenCallEvaluateMethod_thenSuccess() {
    Expression expression = new ExpressionBuilder("3x+2y")
      .variables("x", "y")
      .build()
      .setVariable("x", 2)
      .setVariable("y", 3);
 
    double result = expression.evaluate();
 
    Assertions.assertEquals(12, result);
}

В приведенном выше примере мы вводим две переменные, x и y, используя метод переменных . Мы можем добавить в выражение столько переменных, сколько нам нужно, используя этот метод. Как только мы объявили переменные, мы можем присвоить им значения, используя метод setVariable.

2.4. Вычисление выражений, содержащих математические функции

Давайте теперь рассмотрим краткий пример того, как мы можем вычислить некоторые стандартные математические функции:

@Test
public void givenMathFunctions_whenCallEvaluateMethod_thenSuccess() {
    Expression expression = new ExpressionBuilder("sin(x)*sin(x)+cos(x)*cos(x)")
      .variables("x")
      .build()
      .setVariable("x", 0.5);
 
    double result = expression.evaluate();
 
    Assertions.assertEquals(1, result);
}

3. Javaluator

Javaluator — еще одна независимая и легкая библиотека, доступная бесплатно. Как и exp4j, Javaluator также используется для вычисления инфиксных выражений.

3.1. Добавление зависимости Maven

Мы можем использовать следующую зависимость Maven для использования Javaluator в нашем проекте:

<dependency>
    <groupId>com.fathzer</groupId>
    <artifactId>javaluator</artifactId>
    <version>3.0.3</version>
</dependency>

3.2. Оценка простых выражений

Чтобы оценить выражения с помощью Javaluator, нам сначала нужно создать экземпляр DoubleEvaluator:

@Test
public void givenExpression_whenCallEvaluateMethod_thenSuccess() {
    String expression = "3+2";
    DoubleEvaluator eval = new DoubleEvaluator();
 
    Double result = eval.evaluate(expression);
 
    Assertions.assertEquals(5, result);
}

3.3. Вычисление выражений, содержащих переменные

Для вычисления выражений, содержащих переменные, мы используем StaticVariableSet:

@Test
public void givenVariables_whenCallEvaluateMethod_thenSuccess() {
    String expression = "3*x+2*y";
    DoubleEvaluator eval = new DoubleEvaluator();
    StaticVariableSet<Double> variables = new StaticVariableSet<Double>();
    variables.set("x", 2.0);
    variables.set("y", 3.0);
 
    Double result = eval.evaluate(expression, variables);
 
    Assertions.assertEquals(12, result);
}

Затем мы используем метод StaticVariableSet#set для присвоения значений переменным.

3.4. Вычисление выражений, содержащих математические функции

Мы также можем решать выражения, содержащие математические функции, используя библиотеку Javaluator:

@Test
public void givenMathFunction_whenCallEvaluateMethod_thenSuccess() {
    String expression = "sin(x)*sin(x)+cos(x)*cos(x)";
    DoubleEvaluator eval = new DoubleEvaluator();
    StaticVariableSet<Double> variables = new StaticVariableSet<Double>();
    variables.set("x", 0.5);
 
    Double result = eval.evaluate(expression, variables);
 
    Assertions.assertEquals(1, result);
}

4. Java Scripting API

Теперь, когда мы обсудили сторонние библиотеки, давайте теперь обсудим как мы можем добиться этого с помощью встроенного API. Java уже поставляется с небольшим, но мощным API сценариев. Все классы и интерфейсы этого API находятся в пакете javax.script.

Он содержит интерфейсы ScriptEngineManager и ScriptEngine, которые позволяют нам оценивать JavaScript. До Java 8 Java поставлялась с движком Rhino. Однако, начиная с Java 8, Java поставляется с более новым и мощным движком Nashorn.

4.1. Получение экземпляра ScriptEngine

Чтобы создать ScriptEngine, нам сначала нужно создать экземпляр ScriptEngineManager. Получив экземпляр, нам нужно вызвать метод ScriptEngineManager#getEngineByName, чтобы получить ScriptEngine:

ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
ScriptEngine scriptEngine = scriptEngineManager.getEngineByName("JavaScript");

Обратите внимание, что Nashorn — это механизм JavaScript по умолчанию, который поставляется вместе с JDK.

4.2. Вычисление простых выражений

Теперь мы можем использовать приведенный выше экземпляр scriptEngine для вызова метода ScriptEngine#eval:

String expression = "3+2";
Integer result = (Integer) scriptEngine.eval(expression);
Assertions.assertEquals(5, result);

4.3. Вычисление выражений, содержащих переменные

Для вычисления выражений, содержащих переменные, нам нужно объявить и инициализировать переменные:

String expression = "x=2; y=3; 3*x+2*y;";
Double result = (Double) scriptEngine.eval(expression);
Assertions.assertEquals(12, result);

Поскольку мы используем движок JavaScript, мы можем напрямую добавлять переменные в выражения, как мы это делаем в JavaScript.

«Примечание. JavaScript не имеет прямых методов для выполнения математических операций и требует доступа к объекту Math. Таким образом, мы не можем решать математические выражения с помощью Java Scripting API.

5. Заключение

В этой статье мы рассмотрели различные методы вычисления математических выражений с помощью Java.

Как всегда, полный код этого примера доступен на GitHub.