Java带括号算术表达式计算器代码故障排查求助
看起来你的计算器核心逻辑方向是对的,但几个关键的Java语法错误和逻辑漏洞导致了结果异常,咱们一步步来修复:
1. 最致命的错误:字符串比较用==而非equals()
在Java里,==比较的是字符串对象的内存地址,而不是内容。你所有判断运算符、括号的地方都用了==,导致这些条件永远不成立——运算符根本没被压入栈,也没执行任何运算,最后栈里只剩最后一个输入的数字,自然返回它。
比如:
// 错误写法 return (str == "(" || str == ")" || str == "^" || str == "*" || str == "/" || str == "+" || str == "-"); // 正确写法 return ("(".equals(str) || ")".equals(str) || "^".equals(str) || "*".equals(str) || "/".equals(str) || "+".equals(str) || "-".equals(str));
所有涉及字符串比较的方法(isValidOp、prec、applyOperator、evaluate里的条件判断)都要改成用equals()。
2. 右括号)的处理逻辑错误
你现在遇到)只弹出一个运算符计算,但正确逻辑是一直弹出运算符并计算,直到遇到对应的(,最后还要把(弹出(不参与计算)。原代码会漏掉中间的运算符,还会把(留在栈里导致后续计算错误。
修正后的右括号处理:
if (")".equals(tokens[i])) { // 循环弹出运算符直到遇到左括号 while (!ops.isEmpty() && !"(".equals(ops.peek())) { String op = ops.pop(); double right = nums.pop(); double left = nums.pop(); nums.push(applyOperator(left, op, right)); } // 弹出左括号,不参与计算 if (!ops.isEmpty()) { ops.pop(); } else { // 没有匹配的左括号,抛出异常 throw new IllegalArgumentException("Missing matching '('"); } }
3. 运算符优先级处理不完整
原代码中,当当前运算符优先级小于等于栈顶时,只处理一次就停止了,但实际上应该循环处理所有优先级更高或相等的栈顶运算符(除了左括号),否则会有多个高优先级运算符没被计算。
修正后的运算符处理逻辑:
if ("+".equals(tokens[i]) || "-".equals(tokens[i]) || "*".equals(tokens[i]) || "/".equals(tokens[i]) || "^".equals(tokens[i])) { // 循环处理栈中优先级 >= 当前运算符的运算符(除了左括号) while (!ops.isEmpty() && !"(".equals(ops.peek()) && prec(tokens[i]) <= prec(ops.peek())) { String op = ops.pop(); double right = nums.pop(); double left = nums.pop(); nums.push(applyOperator(left, op, right)); } ops.push(tokens[i]); }
4. 实例变量未重置导致多次计算错误
你的nums和ops是类的实例变量,每次调用evaluate时不会自动清空,第二次计算时栈里还留着上次的数据,导致结果混乱。需要在evaluate方法开头清空两个栈:
public String evaluate(String str) { // 每次计算前清空栈 nums.clear(); ops.clear(); String[] tokens = str.split(" "); // ... 后续代码 }
5. 添加输入异常处理
针对你提到的括号不匹配、运算符异常等问题,我们可以在关键节点抛出异常:
- 遇到右括号但栈空(无匹配左括号)
- 计算时数字栈元素不足(比如表达式
3 +) - 栈里剩余运算符但数字不足
- 除数为零(在
applyOperator的除法分支添加判断) - 遇到无效的 token(既不是数字也不是合法运算符)
比如在evaluate的循环里添加无效token判断:
for (int i = 0; i < tokens.length; i++) { String token = tokens[i]; if (isDouble(token)) { nums.push(Double.parseDouble(token)); } else if ("(".equals(token)) { ops.push(token); } else if (")".equals(token)) { // ... 右括号处理 } else if (isValidOp(token)) { // ... 运算符处理 } else { throw new IllegalArgumentException("Invalid token: " + token); } }
在applyOperator的除法分支添加除数为零判断:
if ("/".equals(op)) { if (right == 0) { throw new ArithmeticException("Division by zero"); } return left / right; }
完整修正后的代码
Calculator类
import java.util.Stack; public class Calculator { // 实例变量 private Stack<Double> nums; private Stack<String> ops; // 构造函数 public Calculator() { nums = new Stack<>(); ops = new Stack<>(); } // 判断是否为数字 public static boolean isDouble(String str) { if (str == null || str.isEmpty()) { return false; } try { Double.parseDouble(str); return true; } catch (NumberFormatException e) { return false; } } // 判断是否为合法运算符/括号 public static boolean isValidOp(String str) { return "(".equals(str) || ")".equals(str) || "^".equals(str) || "*".equals(str) || "/".equals(str) || "+".equals(str) || "-".equals(str); } // 运算符优先级 public int prec(String str) { if ("(".equals(str) || ")".equals(str)) return 4; if ("^".equals(str)) return 3; if ("*".equals(str) || "/".equals(str)) return 2; if ("+".equals(str) || "-".equals(str)) return 1; return -1; } // 执行运算 public double applyOperator(double left, String op, double right) { switch (op) { case "+": return left + right; case "-": return left - right; case "*": return left * right; case "/": if (right == 0) { throw new ArithmeticException("Division by zero"); } return left / right; case "^": return Math.pow(left, right); default: throw new IllegalArgumentException("Invalid operator: " + op); } } // 求值方法 public String evaluate(String str) { // 每次计算前清空栈 nums.clear(); ops.clear(); String[] tokens = str.split(" "); for (String token : tokens) { if (isDouble(token)) { nums.push(Double.parseDouble(token)); } else if ("(".equals(token)) { ops.push(token); } else if (")".equals(token)) { // 处理右括号,直到遇到左括号 while (!ops.isEmpty() && !"(".equals(ops.peek())) { String op = ops.pop(); if (nums.size() < 2) { throw new IllegalArgumentException("Invalid expression: missing operands"); } double right = nums.pop(); double left = nums.pop(); nums.push(applyOperator(left, op, right)); } // 弹出左括号 if (ops.isEmpty()) { throw new IllegalArgumentException("Unmatched ')'"); } ops.pop(); } else if (isValidOp(token)) { // 处理运算符优先级 while (!ops.isEmpty() && !"(".equals(ops.peek()) && prec(token) <= prec(ops.peek())) { String op = ops.pop(); if (nums.size() < 2) { throw new IllegalArgumentException("Invalid expression: missing operands"); } double right = nums.pop(); double left = nums.pop(); nums.push(applyOperator(left, op, right)); } ops.push(token); } else { throw new IllegalArgumentException("Invalid token: " + token); } } // 处理剩余的运算符 while (!ops.isEmpty()) { String op = ops.pop(); if (nums.size() < 2) { throw new IllegalArgumentException("Invalid expression: missing operands"); } double right = nums.pop(); double left = nums.pop(); nums.push(applyOperator(left, op, right)); } // 最后栈里应该只剩一个结果 if (nums.size() != 1) { throw new IllegalArgumentException("Invalid expression: extra operands"); } return nums.pop().toString(); } }
AppforCalc测试类(添加异常捕获)
import javax.swing.JOptionPane; public class AppforCalc { public static void main(String[] args) { Calculator calc = new Calculator(); String reply = "yes"; String instructions = "Enter a mathematical expression. Separate everything with spaces"; while (reply.equalsIgnoreCase("yes")) { String expression = JOptionPane.showInputDialog(instructions); if (expression == null) { break; // 用户点击取消,退出循环 } try { String ans = calc.evaluate(expression); reply = JOptionPane.showInputDialog("The solution is " + ans + "\nTry again?"); } catch (Exception e) { reply = JOptionPane.showInputDialog("Error: " + e.getMessage() + "\nTry again?"); } } } }
现在测试9 * 5、(7 * 6) + (9 - 4)这些表达式应该能得到正确结果,同时遇到(3 + 4(缺右括号)、5 / 0(除零)、3 + * 4(无效运算符)等情况会给出错误提示。
内容的提问来源于stack exchange,提问作者rmcnary4231

