OpenJDK 18下如何动态执行字符串数学公式并转为字符串结果?
问题:动态执行含数学公式的字符串(OpenJDK 18,禁用ScriptEngine)
我有一个包含数学公式的字符串,希望动态执行该公式并将结果存储为字符串。示例如下:
String formula = "10 * 9"; ...(执行操作) String result = "90"; // 执行成功后
我使用OpenJDK 18,无法使用ScriptEngine,请问还有其他实现方法吗?
补充说明:支持+、-、*、/、%、^运算及括号,例如((12/4) * (3 - 1) ^3)。
实现方案
方案一:手动实现表达式解析与计算(无依赖)
如果不想引入第三方库,可以手动实现**逆波兰表达式(后缀表达式)**的转换与计算逻辑,全程无需依赖ScriptEngine,完全自定义控制运算规则。
以下是完整的Java实现代码:
import java.util.ArrayDeque; import java.util.Deque; import java.util.HashMap; import java.util.Map; public class ManualFormulaEvaluator { // 定义运算符优先级,数字越大优先级越高 private static final Map<Character, Integer> OPERATOR_PRIORITY = new HashMap<>(); static { OPERATOR_PRIORITY.put('+', 1); OPERATOR_PRIORITY.put('-', 1); OPERATOR_PRIORITY.put('*', 2); OPERATOR_PRIORITY.put('/', 2); OPERATOR_PRIORITY.put('%', 2); OPERATOR_PRIORITY.put('^', 3); // 幂运算优先级最高 } public static String evaluate(String formula) { // 步骤1:将中缀表达式转换为逆波兰表达式 Deque<Character> operatorStack = new ArrayDeque<>(); StringBuilder rpn = new StringBuilder(); int n = formula.length(); int i = 0; while (i < n) { char c = formula.charAt(i); if (Character.isDigit(c) || c == '.') { // 处理多位数或小数 while (i < n && (Character.isDigit(formula.charAt(i)) || formula.charAt(i) == '.')) { rpn.append(formula.charAt(i)); i++; } rpn.append(' '); // 用空格分隔数字,方便后续拆分 } else if (c == '(') { operatorStack.push(c); i++; } else if (c == ')') { // 弹出运算符直到遇到左括号 while (!operatorStack.isEmpty() && operatorStack.peek() != '(') { rpn.append(operatorStack.pop()).append(' '); } operatorStack.pop(); // 移除左括号 i++; } else if (OPERATOR_PRIORITY.containsKey(c)) { // 弹出优先级不低于当前运算符的栈顶元素 while (!operatorStack.isEmpty() && operatorStack.peek() != '(' && OPERATOR_PRIORITY.get(operatorStack.peek()) >= OPERATOR_PRIORITY.get(c)) { rpn.append(operatorStack.pop()).append(' '); } operatorStack.push(c); i++; } else if (Character.isWhitespace(c)) { // 忽略公式中的空格 i++; } else { throw new IllegalArgumentException("无效字符:" + c); } } // 弹出栈中剩余的所有运算符 while (!operatorStack.isEmpty()) { rpn.append(operatorStack.pop()).append(' '); } // 步骤2:计算逆波兰表达式的结果 Deque<Double> numStack = new ArrayDeque<>(); String[] tokens = rpn.toString().split("\\s+"); for (String token : tokens) { if (token.isEmpty()) continue; if (OPERATOR_PRIORITY.containsKey(token.charAt(0)) && token.length() == 1) { // 处理运算符 char op = token.charAt(0); double b = numStack.pop(); double a = numStack.pop(); double res = switch (op) { case '+' -> a + b; case '-' -> a - b; case '*' -> a * b; case '/' -> a / b; case '%' -> a % b; case '^' -> Math.pow(a, b); default -> throw new IllegalArgumentException("无效运算符:" + op); }; numStack.push(res); } else { // 处理数字 numStack.push(Double.parseDouble(token)); } } double result = numStack.pop(); // 自动判断是否为整数,返回对应格式的字符串 return result == Math.floor(result) ? String.valueOf((long) result) : String.valueOf(result); } public static void main(String[] args) { String formula1 = "10 * 9"; System.out.println(evaluate(formula1)); // 输出 "90" String formula2 = "((12/4) * (3 - 1) ^3)"; System.out.println(evaluate(formula2)); // 输出 "24" } }
方案二:使用轻量级第三方表达式计算库
如果允许引入第三方依赖,可以选择像Exp4j这样的轻量级库,它专门用于解析和计算数学表达式,无需依赖ScriptEngine,兼容OpenJDK 18,且支持所有你需要的运算符和括号。
以下是使用Exp4j的示例代码:
import net.objecthunter.exp4j.Expression; import net.objecthunter.exp4j.ExpressionBuilder; public class FormulaEvaluator { public static String evaluateFormula(String formula) { Expression expression = new ExpressionBuilder(formula) .build(); double result = expression.evaluate(); // 处理整数/小数格式 return result == Math.floor(result) ? String.valueOf((long) result) : String.valueOf(result); } public static void main(String[] args) { String formula = "((12/4) * (3 - 1) ^3)"; String result = evaluateFormula(formula); System.out.println(result); // 输出 "24" } }
使用前需要在项目中引入Exp4j的依赖(例如Maven依赖):
<dependency> <groupId>net.objecthunter</groupId> <artifactId>exp4j</artifactId> <version>0.4.8</version> </dependency>
内容的提问来源于stack exchange,提问作者Biggy Poopa
相关产品推荐
相关产品推荐

