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

递归式数学表达式求值方法仅单次调用正常,多次调用触发EmptyStackException问题排查

解决多次调用parse方法时的EmptyStackException问题

你的问题根源非常明确:静态变量的跨调用状态污染。

你把ops、vals这两个栈,还有遍历用的索引i都声明成了static类变量。这意味着这些变量的生命周期和整个Evaluate类绑定,而不是每次parse方法调用的独立实例。第一次调用parse后,栈里可能残留着上次计算的元素,索引i也停留在上一次处理的位置。当你第二次调用parse时,程序会直接复用这些旧状态:

  • i不是从0开始遍历新的表达式字符数组,导致跳过开头的字符,甚至超出数组范围
  • ops或vals栈里的残留数据会干扰新表达式的计算,当你执行pop()或peek()时,就可能触发EmptyStackException(比如栈已经空了但还试图弹出元素)

修复方案:把状态变量移到方法内部

只需要把这些静态变量移到parse方法里面,让每次调用都创建全新的栈和索引,就能彻底解决问题。修改后的完整代码如下:

public class Evaluate {
    public static void main(String[] args) {
        System.out.println(parse("(4-(7-1))"));
        System.out.println(parse("8"));
        System.out.println(parse("((1+1)*(2*2))"));
        System.out.print("\n");
        System.out.println(parse("(6/(3/2))"));
    }

    private static int parse(String expression) {
        // 每次调用都创建新的栈和索引,避免状态污染
        Stack<Character> ops = new Stack<Character>();
        Stack<Integer> vals = new Stack<Integer>();
        int i = 0;
        
        char[] tokens = expression.toCharArray();
        while (tokens.length > i) {
            char s = tokens[i];
            if (s == '(') {
                ops.push(tokens[i]);
            } else if (s == '+' || s == '-' || s == '*' || s == '/') {
                while (!ops.empty() && hasPrecedence(tokens[i], ops.peek()))
                    vals.push(applyOp(ops.pop(), vals.pop(), vals.pop()));
                ops.push(s);
            } else if (s == ')') {
                char op = ops.pop();
                int v = vals.pop();
                while (ops.peek() != '(')
                    vals.push(applyOp(ops.pop(), vals.pop(), vals.pop()));
                ops.pop();
                if (op == '+') {
                    v = vals.pop() + v;
                } else if (op == '-') {
                    v = vals.pop() - v;
                } else if (op == '*') {
                    v = vals.pop() * v;
                } else if (op == '/') {
                    v = vals.pop() / v;
                }
                vals.push(v);
            } else {
                vals.push(Character.getNumericValue(s));
            }
            i++;
        }
        while (!ops.empty())
            vals.push(applyOp(ops.pop(), vals.pop(), vals.pop()));
        return vals.pop();
    }

    public static boolean hasPrecedence(char op1, char op2) {
        if (op2 == '(' || op2 == ')')
            return false;
        if ((op1 == '*' || op1 == '/') && (op2 == '+' || op2 == '-'))
            return false;
        else
            return true;
    }

    public static int applyOp(char op, int b, int a) {
        switch (op) {
            case '+':
                return a + b;
            case '-':
                return a - b;
            case '*':
                return a * b;
            case '/':
                if (b == 0)
                    throw new UnsupportedOperationException("Cannot divide by zero");
                return a / b;
        }
        return 0;
    }
}

修改关键点说明

  • 移除了类级别的static变量ops、vals、i,将它们声明在parse方法内部
  • 每次调用parse时,都会初始化全新的栈和索引i=0,确保每个表达式的计算都是独立的,不会受到之前调用的影响

现在你可以运行修改后的代码,多次调用parse方法都能正常计算,不会再抛出EmptyStackException了。

内容的提问来源于stack exchange,提问作者Miguel Bets

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 15:57:28