首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

Java Applet 計算機程式除錯指南:生命週期、事件處理與現代化替代方案

     編輯:程式設計綜合問答

程式碼問題診斷

提供的程式碼是一個基於 java.applet.Applet 與 AWT/Swing 混用的計算機,**Applet 技術自 Java 9 起被標記移除,Java 11 完全移除**,現代瀏覽器均不支援。運行時出現的警告:

無法讀取 AppletViewer 的屬性檔案:C:\Users\Administrator.hotjava\properties 使用預設值。

僅為 AppletViewer 設定檔缺失,**非程式邏輯錯誤**,程式實際可在 AppletViewer 中運行。

核心架構缺陷與修正建議

問題現狀建議修正
技術棧過時Applet + AWT + Swing 混用遷移至 JavaFX / Swing 桌面應用 / Web (Spring Boot + Vue/React)
事件處理冗長20+ 個獨立 pressX() 方法 + 巨大 if-else 鏈統一事件處理器、命令模式、Lambda 表達式
狀態管理分散str, sign, num, change 分散欄位封裝 CalculatorModel 類別、狀態機模式
數值精度風險Double.parseDouble + 直接運算使用 BigDecimal 處理金融/精確計算
UI 佈局硬編碼GridLayout + setBounds 混用使用 BorderLayout + GridBagLayout / JavaFX FXML
錯誤處理缺失除零、溢位、非數字輸入無處理try-catch、輸入驗證、使用者友善提示

重構核心:現代 Swing 計算機範例

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.function.BinaryOperator;

public class ModernCalculator extends JFrame {
    private JTextField display;
    private BigDecimal operand1 = null;
    private BinaryOperator<BigDecimal> pendingOp = null;
    private boolean startNewInput = true;

    public ModernCalculator() {
        setTitle("現代計算機");
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLayout(new BorderLayout());

        // 顯示器
        display = new JTextField("0");
        display.setEditable(false);
        display.setHorizontalAlignment(JTextField.RIGHT);
        display.setFont(new Font("Monospaced", Font.PLAIN, 24));
        add(display, BorderLayout.NORTH);

        // 按鈕面板
        JPanel buttonPanel = new JPanel(new GridLayout(5, 4, 5, 5));
        String[] buttons = {
            "7", "8", "9", "/",
            "4", "5", "6", "*",
            "1", "2", "3", "-",
            "0", ".", "=", "+",
            "C", "⌫", "%", "±"
        };

        for (String text : buttons) {
            JButton btn = new JButton(text);
            btn.setFont(new Font("SansSerif", Font.BOLD, 18));
            btn.addActionListener(this::handleButton);
            buttonPanel.add(btn);
        }
        add(buttonPanel, BorderLayout.CENTER);

        pack();
        setLocationRelativeTo(null);
        setResizable(false);
    }

    private void handleButton(ActionEvent e) {
        String cmd = e.getActionCommand();
        switch (cmd) {
            case "0": case "1": case "2": case "3": case "4":
            case "5": case "6": case "7": case "8": case "9":
                inputDigit(cmd); break;
            case ".": inputDecimal(); break;
            case "+": case "-": case "*": case "/":
                inputOperator(cmd); break;
            case "=": calculateResult(); break;
            case "C": clearAll(); break;
            case "⌫": backspace(); break;
            case "%": percent(); break;
            case "±": toggleSign(); break;
        }
    }

    private void inputDigit(String digit) {
        if (startNewInput) {
            display.setText(digit);
            startNewInput = false;
        } else {
            if (!"0".equals(display.getText()))
                display.setText(display.getText() + digit);
        }
    }

    private void inputDecimal() {
        if (startNewInput) { display.setText("0."); startNewInput = false; }
        else if (!display.getText().contains(".")) display.setText(display.getText() + ".");
    }

    private void inputOperator(String op) {
        if (operand1 != null && !startNewInput) calculateResult();
        operand1 = new BigDecimal(display.getText());
        pendingOp = switch (op) {
            case "+" -> BigDecimal::add;
            case "-" -> BigDecimal::subtract;
            case "*" -> BigDecimal::multiply;
            case "/" -> (a, b) -> a.divide(b, 10, RoundingMode.HALF_UP);
            default -> null;
        };
        startNewInput = true;
    }

    private void calculateResult() {
        if (operand1 == null || pendingOp == null) return;
        BigDecimal operand2 = new BigDecimal(display.getText());
        try {
            BigDecimal result = pendingOp.apply(operand1, operand2);
            display.setText(stripTrailingZeros(result));
        } catch (ArithmeticException ex) {
            display.setText("Error");
        }
        operand1 = null;
        pendingOp = null;
        startNewInput = true;
    }

    private String stripTrailingZeros(BigDecimal bd) {
        return bd.stripTrailingZeros().toPlainString();
    }

    private void clearAll() { display.setText("0"); operand1 = null; pendingOp = null; startNewInput = true; }
    private void backspace() { if (!startNewInput && display.getText().length() > 1) display.setText(display.getText().substring(0, display.getText().length()-1)); else display.setText("0"); }
    private void percent() { if (!startNewInput) { BigDecimal v = new BigDecimal(display.getText()).divide(BigDecimal.valueOf(100)); display.setText(stripTrailingZeros(v)); } }
    private void toggleSign() { if (!startNewInput) { BigDecimal v = new BigDecimal(display.getText()).negate(); display.setText(stripTrailingZeros(v)); } }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new ModernCalculator().setVisible(true));
    }
}

關鍵改進點解析

  1. 單一事件處理器:handleButton 透過 ActionCommand 分派,消除 20+ 個獨立方法。
  2. BigDecimal 精確運算:避免 double 浮點誤差(如 0.1+0.2=0.30000000000000004)。
  3. 狀態封裝:operand1, pendingOp, startNewInput 清楚定義計算機狀態。
  4. 函數式運算子:BinaryOperator<BigDecimal> + Lambda 取代巨大 switch。
  5. 標準桌面應用:繼承 JFrame,main 啟動,無需瀏覽器/AppletViewer。
  6. EDT 安全啟動:SwingUtilities.invokeLater 確保執行緒安全。

遷移路徑建議

目標平台技術棧學習曲線適用場景
桌面應用Swing (如上) / JavaFX (FXML + CSS)低/中內部工具、離線應用、嵌入式介面
Web 應用Spring Boot + Vue 3 / React + TypeScript中高跨平台、協作、雲端部署、手機適配
行動應用Android (Kotlin/Jetpack Compose) / Flutter / React Native中高原生體驗、離線優先、應用商店分發

總結

原程式碼雖能在 AppletViewer 運行,但**技術棧已淘汰、架構不佳、維護困難**。建議直接重寫為現代 Swing/JavaFX 桌面應用或 Web 應用。上述重構範例展示了:事件統一分派、精確數值運算、狀態封裝、函數式策略模式等專業開發實踐,可作為學習遷移的起點。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved