ScriptEngineManager)执行运算,将结果输出至显示区域,需注意异常捕获与精度
在 Java 中实现计算器的 功能需要结合 界面交互逻辑、数学运算规则 和 状态管理机制,以下是详细的实现方案,涵盖核心思路、代码结构和关键细节:
核心设计目标
按钮的核心作用是 触发最终计算,其行为需满足以下场景:
| 用户操作序列 | 预期行为 |
|—————————-|————————————————————————–|
| 3 → → 5 → | 计算 3+5=8,显示结果 |
| 6 → → 4 → | 计算 6×4=24,显示结果 |
| 9 → → 2 → | 计算 9-2=7,显示结果 |
| 10 → → 2 → | 计算 10÷2=5,显示结果 |
| 5 → → | 无有效第二个操作数,视为无效操作(或保留原值) |
| 8 → | 仅单个数字,直接返回该数字 |
| 7 → → 3 → → → 2 → | 链式计算:(7+3)=10 → 10×2=20 |
关键技术组件
界面元素(基于 Swing)
// 主窗口与组件声明
JFrame frame = new JFrame("Calculator");
JTextField display = new JTextField(); // 显示区
JPanel buttonPanel = new JPanel(); // 按钮面板
String[] buttons = {"7", "8", "9", "/", "4", "5", "6", "", "1", "2", "3", "-", "0", ".", "=", "+"};
状态管理变量
| 变量名 | 类型 | 用途说明 |
|---|---|---|
currentInput |
String | 暂存当前正在输入的数字(含小数点) |
storedValue |
double | 存储第一个操作数(用于二元运算) |
selectedOp |
char | 记录已选择的运算符(’+’, ‘-‘, ”, ‘/’) |
isNewEntry |
boolean | 标记是否为新输入(区分连续输入与新运算) |
hasOperator |
boolean | 标记是否已选择运算符(决定能否执行计算) |
事件分发机制
通过 ActionListener 统一处理所有按钮点击事件:
for (String btnText : buttons) {
JButton btn = new JButton(btnText);
btn.addActionListener(e -> handleButtonClick((String) e.getActionCommand()));
buttonPanel.add(btn);
}
按钮的核心逻辑实现
伪代码流程
当点击 "=" 时:
hasOperator 为 false:
说明只有单个数字 → 直接显示 currentInput
否则:
将 currentInput 转换为 double 类型的 secondOperand
根据 selectedOp 执行对应运算:
case '+': result = storedValue + secondOperand
case '-': result = storedValue secondOperand
case '': result = storedValue secondOperand
case '/': 检查除数是否为0 → 若为0则报错,否则计算商
显示结果,并将结果存入 storedValue 供后续连锁运算
重置 currentInput 和 hasOperator 状态
完整 Java 实现代码段
private void handleEquals() {
if (!hasOperator) {
// 无运算符,直接显示当前输入
display.setText(currentInput);
return;
}
try {
double secondOperand = Double.parseDouble(currentInput);
double result = 0;
switch (selectedOp) {
case '+':
result = storedValue + secondOperand;
break;
case '-':
result = storedValue secondOperand;
break;
case '':
result = storedValue secondOperand;
break;
case '/':
if (secondOperand == 0) throw new ArithmeticException("Division by zero");
result = storedValue / secondOperand;
break;
}
// 更新显示并准备下次运算
display.setText(String.valueOf(result));
storedValue = result;
currentInput = String.valueOf(result); // 允许连锁运算
hasOperator = false; // 重置运算符状态
} catch (NumberFormatException ex) {
display.setText("Error");
} catch (ArithmeticException ex) {
display.setText(ex.getMessage());
}
}
配套辅助方法
数字/小数点输入处理
private void handleDigit(String input) {
if (input.equals(".") && currentInput.contains(".")) return; // 防止重复小数点
currentInput += input;
display.setText(currentInput);
isNewEntry = false; // 标记为非新输入
}
运算符选择处理
private void handleOperator(char op) {
if (isNewEntry) {
// 新运算开始,保存当前值为第一个操作数
storedValue = Double.parseDouble(currentInput);
} else {
// 已有未完成的运算,先计算旧运算再保存新状态
handleEquals(); // 隐式执行上一次运算
}
selectedOp = op;
hasOperator = true;
isNewEntry = true; // 下一个输入将是新操作数
}
典型场景测试用例
| 输入序列 | 内部状态变化 | 输出结果 |
|---|---|---|
3 → → 5 → |
storedValue=3 → selectedOp=’+’ → currentInput=5 → 计算得8 | 8 |
8 → |
hasOperator=false → 直接显示8 | 8 |
9 → → 2 → |
storedValue=9 → selectedOp=’-‘ → currentInput=2 → 计算得7 | 7 |
7 → → 3 → → → 2 → |
第一次计算得10 → 第二次计算得20 | 20 |
5 → → 0 → |
触发除零异常 → 显示”Division by zero” | Error |
FAQs
Q1: 为什么有时按 后可以直接继续输入新运算符?
A: 这是通过 isNewEntry 标志实现的,当 被按下后,系统会将计算结果同时存入 storedValue 和 currentInput,并将 isNewEntry 设为 true,使得下一次输入运算符时会自动以最新结果作为第一个操作数。
Q2: 如何处理类似 3++5 的错误输入?
A: 在 handleOperator 方法中,当检测到 isNewEntry 为 false(即已有未完成的运算)时,会先调用 handleEquals() 强制完成上一次运算。3++5 会被解释为 (3+5)=8,而非语法错误。
扩展建议
- 历史记录:可添加
ArrayList<String>保存每次计算的历史记录。 - 科学计算:增加三角函数、指数运算等,需引入
Math类库。 - 键盘支持:通过
KeyAdapter映射键盘按键到虚拟按钮。 - 精度控制:使用
BigDecimal替代double避免浮点误差。
此实现方案通过状态机模型管理计算流程,能够准确处理常规四则运算和连锁计算,是工业级计算器应用
