91行Java代码能实现什么?一个功能完整的图形化计算器就是最好的答案。这个项目展示了如何用极简的代码实现一个具备四则运算、错误处理和界面美化的实用工具。作为Java GUI编程的入门项目,它不仅适合初学者理解Swing框架的核心概念,也为有经验的开发者提供了代码优化的参考范例。
这个计算器的核心价值在于其简洁而完整的实现逻辑。从界面布局到事件处理,从输入验证到运算逻辑,每一行代码都经过精心设计,既保证了功能完整性,又避免了冗余代码。特别值得一提的是,项目还包含了错误处理机制和界面美化技巧,这些都是实际开发中容易被忽视但至关重要的细节。
要运行这个计算器项目,你需要准备以下环境:
将代码保存为SimpleCalculator.java后,使用以下命令编译运行:
bash复制javac SimpleCalculator.java
java SimpleCalculator
整个计算器由三个核心部分组成:
BorderLayout作为主容器,顶部显示区域+中部按钮面板ActionListener接口实现按钮点击响应java复制public class SimpleCalculator extends JFrame {
private JTextField display; // 显示区域
private double firstNum = 0; // 第一个操作数
private String operator = ""; // 当前运算符
private boolean startNewNumber = true; // 是否开始新数字输入
// 构造方法初始化界面
public SimpleCalculator() {
setTitle("Java计算器");
setSize(500, 600);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new BorderLayout());
initDisplay(); // 初始化显示区域
initButtons(); // 初始化按钮面板
setVisible(true);
}
// 其他方法实现...
}
显示区域使用JTextField实现,设置为不可编辑状态以防止非法输入:
java复制private void initDisplay() {
display = new JTextField("0");
display.setFont(new Font("Arial", Font.BOLD, 24));
display.setHorizontalAlignment(JTextField.RIGHT);
display.setEditable(false); // 禁止直接编辑
add(display, BorderLayout.NORTH);
}
按钮面板采用4×4网格布局,使用数组定义按钮文本,简化创建过程:
java复制private void initButtons() {
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new GridLayout(4, 4, 5, 5));
String[] buttons = {
"7", "8", "9", "/",
"4", "5", "6", "*",
"1", "2", "3", "-",
"C", "0", "=", "+"
};
for (String text : buttons) {
JButton button = new JButton(text);
button.setFont(new Font("Arial", Font.BOLD, 18));
button.addActionListener(new ButtonClickListener());
buttonPanel.add(button);
}
add(buttonPanel, BorderLayout.CENTER);
}
ButtonClickListener内部类处理所有按钮点击事件,根据按钮类型执行不同操作:
java复制private class ButtonClickListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
String command = e.getActionCommand();
// 数字按钮处理
if ("0123456789".contains(command)) {
handleNumberInput(command);
}
// 清除按钮
else if (command.equals("C")) {
display.setText("0");
firstNum = 0;
operator = "";
startNewNumber = true;
}
// 运算符按钮
else if ("+-*/".contains(command)) {
handleOperator(command);
}
// 等号按钮
else if (command.equals("=")) {
calculate();
operator = "";
startNewNumber = true;
}
}
// 其他处理方法...
}
数字输入需要考虑两种情况:开始新数字输入或在现有数字后追加:
java复制private void handleNumberInput(String digit) {
if (startNewNumber) {
display.setText(digit);
startNewNumber = false;
} else {
display.setText(display.getText() + digit);
}
}
运算符按钮需要保存第一个操作数和运算符,准备接收第二个操作数:
java复制private void handleOperator(String op) {
if (!operator.isEmpty()) {
calculate(); // 如果已有运算符,先计算前一个表达式
}
firstNum = Double.parseDouble(display.getText());
operator = op;
startNewNumber = true; // 准备接收第二个操作数
}
calculate()方法执行实际运算,包含除零错误处理:
java复制private void calculate() {
double secondNum = Double.parseDouble(display.getText());
double result = 0;
switch (operator) {
case "+":
result = firstNum + secondNum;
break;
case "-":
result = firstNum - secondNum;
break;
case "*":
result = firstNum * secondNum;
break;
case "/":
if (secondNum != 0) {
result = firstNum / secondNum;
} else {
display.setText("错误:除零");
return;
}
break;
}
// 处理整数显示
display.setText(result == (int)result ?
String.valueOf((int)result) : String.valueOf(result));
}
Java提供了多种预设界面风格,可以通过一行代码切换:
java复制// 在main方法开始处添加
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
e.printStackTrace();
}
常用LookAndFeel选项:
UIManager.getCrossPlatformLookAndFeelClassName() - Java默认风格UIManager.getSystemLookAndFeelClassName() - 系统原生风格"javax.swing.plaf.nimbus.NimbusLookAndFeel" - 现代化Nimbus风格通过设置字体、颜色和边框提升视觉效果:
java复制// 按钮样式优化示例
JButton button = new JButton(text);
button.setFont(new Font("Segoe UI", Font.PLAIN, 18));
button.setBackground(new Color(240, 240, 240));
button.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createLineBorder(new Color(200, 200, 200)),
BorderFactory.createEmptyBorder(5, 15, 5, 15)
));
button.setFocusPainted(false); // 移除焦点边框
FlatLaf可以提供更现代化的扁平化设计:
xml复制<dependency>
<groupId>com.formdev</groupId>
<artifactId>flatlaf</artifactId>
<version>3.7</version>
</dependency>
java复制FlatLightLaf.setup(); // 浅色主题
// 或
FlatDarkLaf.setup(); // 深色主题
扩展计算器支持三角函数、对数等科学函数:
java复制String[] buttons = {
"sin", "cos", "tan", "√",
"7", "8", "9", "/",
"4", "5", "6", "*",
"1", "2", "3", "-",
"C", "0", "=", "+"
};
java复制else if (command.equals("sin")) {
double value = Double.parseDouble(display.getText());
double result = Math.sin(Math.toRadians(value));
display.setText(String.valueOf(result));
}
else if (command.equals("cos")) {
// 类似实现...
}
else if (command.equals("√")) {
double value = Double.parseDouble(display.getText());
if (value >= 0) {
display.setText(String.valueOf(Math.sqrt(value)));
} else {
display.setText("错误:负数开方");
}
}
修改数字处理逻辑支持小数点:
java复制private void handleNumberInput(String input) {
String current = display.getText();
if (startNewNumber) {
display.setText(input.equals(".") ? "0." : input);
startNewNumber = false;
} else {
if (input.equals(".")) {
if (!current.contains(".")) {
display.setText(current + ".");
}
} else {
display.setText(current + input);
}
}
}
使用JList组件实现计算历史记录:
java复制private JList<String> historyList;
private DefaultListModel<String> historyModel;
private void initHistoryPanel() {
historyModel = new DefaultListModel<>();
historyList = new JList<>(historyModel);
JScrollPane scrollPane = new JScrollPane(historyList);
scrollPane.setPreferredSize(new Dimension(150, 0));
add(scrollPane, BorderLayout.EAST);
}
java复制private void calculate() {
// ...原有计算逻辑...
// 添加历史记录
String record = firstNum + " " + operator + " " + secondNum + " = " + result;
historyModel.addElement(record);
}
问题现象:界面元素不显示或布局错乱
解决方案:
setVisible(true)问题现象:点击按钮无反应
解决方案:
ActionListener问题现象:浮点运算结果不精确
解决方案:
BigDecimal类java复制// 使用BigDecimal进行高精度计算示例
BigDecimal num1 = new BigDecimal("0.1");
BigDecimal num2 = new BigDecimal("0.2");
BigDecimal sum = num1.add(num2); // 0.3,无精度损失
问题现象:长时间运行后内存占用持续增长
解决方案:
对于复杂界面,可以采用延迟加载策略:
java复制// 延迟加载示例
private JPanel createComplexPanel() {
if (complexPanel == null) {
complexPanel = new JPanel();
// 初始化复杂组件...
}
return complexPanel;
}
避免在事件处理方法中执行耗时操作:
java复制button.addActionListener(e -> {
// 立即更新界面反馈
button.setText("处理中...");
// 在后台线程执行耗时操作
SwingUtilities.invokeLater(() -> {
performLongOperation();
button.setText("完成");
});
});
自定义渲染时注意性能:
java复制// 高效的自定义渲染示例
JList<String> list = new JList<>(data);
list.setCellRenderer(new DefaultListCellRenderer() {
@Override
public Component getListCellRendererComponent(JList<?> list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
// 轻量级的渲染逻辑
setText(value.toString());
setIcon(simpleIcon);
return this;
}
});
在实际项目中开发Swing应用时,有几个关键点需要注意:
线程安全:Swing组件必须在事件分发线程(EDT)上操作,使用SwingUtilities.invokeLater()确保线程安全
国际化支持:使用资源束(ResourceBundle)实现多语言支持,方便后期本地化
java复制// 国际化示例
ResourceBundle bundle = ResourceBundle.getBundle("Messages", locale);
JButton button = new JButton(bundle.getString("button.calculate"));
java复制// 可访问性设置示例
JButton button = new JButton("Calculate");
button.getAccessibleContext().setAccessibleDescription("Perform calculation");
java复制// 使用java.util.logging记录日志
private static final Logger logger = Logger.getLogger(SimpleCalculator.class.getName());
// 在关键操作处添加日志
logger.info("Performing calculation: " + expression);
java复制// 加载配置示例
Properties props = new Properties();
try (InputStream in = Files.newInputStream(Paths.get("config.properties"))) {
props.load(in);
String theme = props.getProperty("theme", "default");
// 应用主题...
}
这个91行代码的计算器项目虽然简单,但涵盖了Java GUI开发的核心概念。通过扩展和完善这个基础版本,你可以逐步掌握更复杂的桌面应用开发技巧。在实际开发中,代码的组织和维护同样重要,建议在添加新功能时保持代码的模块化和可测试性。