需求背景与实现目标
背景与目标概览
在 temperature=0.6 的设定下,本文聚焦如何用 Java 实现一个简单计算器,并提供一个易于理解的代码示例。通过从零开始设计,读者可以掌握表达式解析、运算执行以及边界情况处理等要点。四则运算、括号和小数点等基本功能被纳入实现范围,以满足日常计算需求。
本节还明确了实现目标:一个可在命令行直接运行的控制台应用,具备清晰的结构、可维护的代码以及易于扩展的设计。读者将看到从输入清洗、到运算符优先级处理、再到结果输出的完整流程。可直接运行、可扩展、鲁棒性良好是本实现的核心指标。
核心设计与实现思路
表达式解析与运算流程
实现的核心在于将中缀表达式转换为便于计算的形式,并逐步求值。通过两栈结构,可以在不使用外部库的情况下,处理数字、运算符和括号之间的关系。表达式解析和 栈结构是本方案的关键点。
为提升鲁棒性,代码需要处理空格、负数、浮点数以及括号配对等边界情况。通过严格的输入清洗与错误检查,可以在遇到非法字符时给出明确的异常信息。输入清洗、错误检测是实现的安全基线。
环境准备与项目结构
开发环境与依赖
本教程选用常见的 Java 开发环境,推荐 JDK 8 及以上版本实现最广泛的兼容性。唯一的外部依赖是 JDK 自带的集合框架,不需要额外的第三方库。JDK 8+、标准库即可完成实现。
你可以在任意主流 IDE 中创建一个简单的 Java 类并直接粘贴代码,随后通过命令行或 IDE 运行入口来测试表达式的计算结果。跨平台兼容和 快速上手是本实现的设计导向。
核心代码实现
核心类设计与方法概览
为了让实现清晰易懂,核心逻辑集中在一个 Calculator 类中,包含一个 evaluate(String expression) 方法用于计算表达式的值,同时提供 main 方法实现简单的交互式输入。核心方法、边界检查以及 辅助方法共同构成了实现的骨架。
该实现采用两栈法:值栈用于存放数字,操作符栈用于存放运算符。通过处理括号、运算符优先级和端点情况,能够正确求出任意合法表达式的结果。两栈法、运算符优先级、括号匹配是关键点。

import java.util.Stack;public class Calculator {// 判断是否为运算符private static boolean isOperator(char c) {return c == '+' || c == '-' || c == '*' || c == '/';}// 运算符优先级private static int precedence(char op) {switch (op) {case '+':case '-':return 1;case '*':case '/':return 2;default:return -1;}}// 应用一个运算符,将两个数进行运算并压回值栈private static void applyOp(Stack values, Stack ops) {if (values.size() < 2 || ops.isEmpty()) {throw new IllegalArgumentException("表达式格式错误");}double b = values.pop();double a = values.pop();char op = ops.pop();switch (op) {case '+': values.push(a + b); break;case '-': values.push(a - b); break;case '*': values.push(a * b); break;case '/': values.push(a / b); break;default:throw new IllegalArgumentException("未知运算符: " + op);}}// 计算表达式的核心方法,支持小数、负数、括号public static double evaluate(String expression) {if (expression == null) {throw new IllegalArgumentException("表达式为空");}String expr = expression.replaceAll("\\s+", ""); // 去掉空格Stack values = new Stack<>();Stack ops = new Stack<>();int i = 0;while (i < expr.length()) {char ch = expr.charAt(i);// 数字(含小数)if (Character.isDigit(ch) || ch == '.') {int j = i;while (j < expr.length() && (Character.isDigit(expr.charAt(j)) || expr.charAt(j) == '.')) j++;double val = Double.parseDouble(expr.substring(i, j));values.push(val);i = j;continue;}// 括号if (ch == '(') {ops.push(ch);i++;continue;}if (ch == ')') {while (!ops.isEmpty() && ops.peek() != '(') {applyOp(values, ops);}if (ops.isEmpty()) {throw new IllegalArgumentException("括号不匹配");}ops.pop(); // pop '('i++;continue;}// 运算符if (isOperator(ch)) {// 处理一元负号,如 -3 + 5if (ch == '-' && (i == 0 || expr.charAt(i - 1) == '(' || isOperator(expr.charAt(i - 1)))) {int j = i + 1;while (j < expr.length() && (Character.isDigit(expr.charAt(j)) || expr.charAt(j) == '.')) j++;double val = Double.parseDouble(expr.substring(i, j));values.push(val);i = j;continue;}while (!ops.isEmpty() && ops.peek() != '(' &&precedence(ops.peek()) >= precedence(ch)) {applyOp(values, ops);}ops.push(ch);i++;continue;}// 非法字符throw new IllegalArgumentException("无效字符: " + ch);}// 完成计算while (!ops.isEmpty()) {if (ops.peek() == '(' || ops.peek() == ')') {throw new IllegalArgumentException("括号不匹配");}applyOp(values, ops);}if (values.size() != 1) {throw new IllegalArgumentException("表达式计算错误");}return values.pop();}// 简单交互入口,支持多轮输入public static void main(String[] args) throws Exception {java.io.BufferedReader br = new java.io.BufferedReader(new java.io.InputStreamReader(System.in));System.out.println("请输入表达式(示例: 3 + 4 * (2 - 1)),按 Ctrl+C 退出:");String line;while ((line = br.readLine()) != null) {line = line.trim();if (line.isEmpty()) continue;try {double result = evaluate(line);System.out.println("结果: " + result);} catch (Exception ex) {System.out.println("错误: " + ex.getMessage());}System.out.println("继续输入表达式:");}}
}
完整运行示例与测试步骤
示例输入输出与测试要点
在本节中提供一个简要的运行流程,帮助你快速验证实现的正确性。通过命令行编译运行后,输入若干表达式即可看到即时的计算结果。快速验证、边界测试,如括号不配、除零等错误场景是重要的测试点。
典型示例包括简单的算式、带括号的表达式以及带小数点的计算:如 1 + 2 * 3、(1 + 2) * 3、7.5 / 2.5、以及含负数的表达式 -3 + 5 等。通过这些用例可以确认运算优先级、括号处理和负数解析是否正确。示例用例有助于理解实现细节并提升使用信心。
扩展与鲁棒性要点
异常处理与输入校验
为了提升健壮性,代码在遇到非法字符、括号不匹配或运算不足(如除以零)时会抛出明确的异常信息。输入校验、错误提示和 边界处理是实际应用场景中的关键保障。
你可以在此基础上扩展对浮点精度、科学计数法输入(如 1e3)以及高阶算术运算的支持,然而这需要对解析和数值稳定性有更深的考量。数值稳定性与 扩展性是后续可能的改进方向。
性能与兼容性注意事项
该实现使用两个栈进行表达式求值,时间复杂度大致为 O(n),其中 n 是表达式长度。对于普通日常表达式,性能足以胜任。若输入非常长的表达式,仍应尽量避免重复创建对象,以提升性能。时间复杂度与 内存开销是评估点。
兼容性方面,基于标准 Java 集合和基础语法的实现可以在大多数 JRE/JDK 环境中工作。若迁移到极端受限的运行环境,需关注异常处理行为是否与目标平台一致。跨平台兼容与 稳定性是优先考虑的方向。


