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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 05:38:02