递归式数学表达式求值方法仅单次调用正常,多次调用触发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
相关产品推荐
相关产品推荐

