You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 04:07:01