Java计算器

本文介绍了一个简单的Java计算器实现方法,利用后缀表达式进行计算。支持加、减、乘、除和括号,通过100多行代码实现,并提供GitHub上的完整代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本篇博客将利用“后缀表达式”,100多行Java代码(不包括注释)实现一个简单强大的计算器,支持的运算符包括加、减、乘、除、以及小括号。

GitHub代码链接(已经做好封装,可以直接使用)


实现原理及说明:

先将计算式变为程序容易计算的后缀表达式,然后通过后缀表达式进行计算得到结果。

文章分成三部分,第一部分介绍如何将普通的计算式变为后缀表达式,第二部分介绍如何用“程序思维”求解后缀表达式,第三部分为程序实现。

一、后缀表达式

我们平常生活中使用的计算式是叫中缀表达式,像这样8×4-(10+12÷3),变为后缀表达式是这样8 4 × 10 12 3 ÷ + - ,后面这样的表达式就便于我们程序计算了,那么后缀表达式是如何得出的呢?

生成规则(需要用到一个栈):

1.遇到操作数,直接输出; 
2.栈为空时,遇到运算符,直接入栈; 
3.遇到左括号,直接入栈; 
4.遇到右括号,右括号不入栈也不输出,依次弹出栈顶元素直到弹出左括号为止,弹出元素依次输出,左括号不输出; 
5.遇到其他运算符“+”、“-”、“×”、“÷”时,弹出所有优先级大于或等于该运算符的栈顶元素并输出,然后将该运算符入栈; 
6.最终将栈中的剩余元素依次出栈,输出。 

举一个例子,下面的图形代表栈:



以上就是 “原表达式(中缀表达式)”  变为  “后缀表达式” 的一种方法。

二、计算后缀表达式

计算规则(需要用到一个栈):

1.从左至右依次扫描表达式。

2.遇到数字直接入栈。

3.遇到运算符,则从栈中依次取出两个栈顶数字,根据运算符得出两数结果,然后将结果入栈。

4.最终栈中剩余数字就是计算结果。

三、程序实现

1、调用方法:

                String result1 = Calculator.input("8×4-(10+12÷3)").getResult();

                String result2 = Calculator.input("8/3").getResult(3); // 保留三位小数结果

                GitHub代码链接(已经做好封装,可以直接使用)

2、全部代码如下:

package com.csw.calculator;

import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.Stack;

/**
 * 说明:
 *      1.用到了BigDecimal类,它的精度范围比较高,确保计算结果的准确性。
 *      2.关于处理负号,如-5+2,会变为0-5+2,在负号前添0。
 *      3.Main类中有演示使用方法
 * Created by 丛 on 2018/2/12 0012.
 */

public class Calculator {
    private static String formula; // 输入的计算式

    private Calculator() {}

    public static Calculator input(String inputFormula) {
        formula = inputFormula;
        return new Calculator();
    }

    /**
     * 获取结果,带有指定保留位数功能
     * @param accurate 小数点后保留的位数
     * @return 经过小数保留后的字符串结果
     */
    public String getResult(int accurate) {
        if (accurate >= 0)
            return getRawResult().setScale(accurate, RoundingMode.HALF_UP).toPlainString();
        else
            return getResult();
    }

    /**
     * 获取结果
     * @return 获取字符串形式的结果
     */
    public String getResult() {
        return getRawResult().stripTrailingZeros().toPlainString();
    }

    /**
     * 获取BigDecimal结果方法
     * @return 以BigDecimal的形式返回结果
     */
    public BigDecimal getRawResult() {
        handleFormula(); // 将字符串计算式中的空格处理掉,为生成后缀表达式做一些处理。
        getSuffixFormula(); // 生成后缀表达式计算公式字符串,便于程序处理。
        return calculate(); // 返回计算结果
    }

    /**
     * 将输入计算式中的每个数字以“_”结尾,表示一个数字结束,方便得到后缀表达式以及计算结果
     */
    private void handleFormula() {
        formula = formula.replace(" ", ""); // 处理计算式中的空格
        formula = formula.replace("×", "*"); // 将×替换为*用于计算
        formula = formula.replace("÷", "/"); // 将÷替换为/用于计算
        if (formula.charAt(0) == '-') { // 计算式以负号开头,在前面加0
            formula = "0" + formula;
        }
        // 处理负号前面是括号的情况
        formula = formula.replace("(-", "(0-");
        // 下面5种运算符前可能是数字,在前面加下划线"_"
        formula = formula.replace("+", "_+");
        formula = formula.replace("-", "_-");
        formula = formula.replace("*", "_*");
        formula = formula.replace("/", "_/");
        formula = formula.replace(")", "_)");
        formula += "_"; // 计算式结尾可能是数字,结尾后加"下划线_"
        // 计算式如果带括号,上面加的下划线可能没有加在数字后面,纠正一下
        if (formula.contains("(") || formula.contains(")")) {
            formula = formula.replace(")_+", ")+"); // 加号的左面是括号
            formula = formula.replace(")_-", ")-"); // 减号的左面是括号
            formula = formula.replace(")_*", ")*"); // 乘号的左面是括号
            formula = formula.replace(")_/", ")/"); // 除号的左面是括号
            formula = formula.replace(")_", ")"); // 结尾是括号
        }
    }

    /**
     * 获取后缀表达式,后缀表达字符串中会保留handleFormula()中的下划线
     * Stack是Java提供的一个实现栈效果的类,stack.push(xxx)是入栈,stack.pop(xxx)是出栈,stack.peek()是查看栈顶元素
     */
    private void getSuffixFormula() {
        StringBuilder suffixFormula = new StringBuilder(); // 后缀表达式字符串
        Stack<Character> stackOperator = new Stack<>();
        for (char c: formula.toCharArray()) { // 将计算式字符串以char型的方式遍历一遍
            if (isNumber(c) || c == '_') { // 当前char为数字或下划线
                suffixFormula.append(c);
            } else if (c == '.') { // 小数点
                suffixFormula.append(c);
            } else if (c == '+' || c == '-') {
                if (stackOperator.empty()) { // 栈为空
                    stackOperator.push(c);
                }
                else {
                    char c1 = stackOperator.peek();
                    while (c1 != '(') { // 是 +、-、*、/ 符号
                        suffixFormula.append(stackOperator.pop());
                        if (stackOperator.empty())
                            break;
                        c1 = stackOperator.peek();
                    }
                    stackOperator.push(c);
                }
            } else if (c == '*' || c == '/') {
                if (stackOperator.empty()) {
                    stackOperator.push(c);
                }
                else {
                    char c1 = stackOperator.peek();
                    while (c1 == '*' || c1 == '/') {
                        suffixFormula.append(stackOperator.pop());
                        if (stackOperator.empty())
                            break;
                        c1 = stackOperator.peek();
                    }
                    stackOperator.push(c);
                }
            } else if (c == '(') {
                stackOperator.push(c);
            } else if (c == ')') { // 不需形成数字添加_,因为 ) 前肯定是数字,后肯定是运算符,形成数字交给后面的运算符处理
                char c1 = stackOperator.peek();
                while (c1 != '(') {
                    suffixFormula.append(stackOperator.pop());
                    if (stackOperator.empty())
                        break;
                    c1 = stackOperator.peek();
                }
                stackOperator.pop(); // 弹出“(”
            }
        }
        while (!stackOperator.empty())
            suffixFormula.append(stackOperator.pop());
        formula = suffixFormula.toString(); // 将后缀表达式赋予全局计算式,后缀表达式中会保留下划线
    }

    /**
     * 最后的计算方法,得到计算结果
     */
    private BigDecimal calculate() {
        Stack<BigDecimal> stackNumber = new Stack<>();
        Stack<Character> stackSingleNumber = new Stack<>();
        int intBit = 1; // 整数部分位数
        int dotBit = 0; // 小数部分位数
        for (char c: formula.toCharArray()) {
            if (isNumber(c) || c == '.') {
                stackSingleNumber.push(c);
            } else if (c == '_') {
                BigDecimal b = new BigDecimal(String.valueOf(stackSingleNumber.pop() - 48)); // char转int

                while (!stackSingleNumber.empty()) {
                    char c1 = stackSingleNumber.pop();
                    if (c1 != '.') {                // char转int
                        b = b.add(new BigDecimal(String.valueOf(c1 - 48)).multiply(new BigDecimal("10").pow(intBit)));
                        intBit++;
                    } else {
                        dotBit = intBit;
                    }
                }
                if (dotBit != 0)
                    b = b.multiply(new BigDecimal("0.1").pow(dotBit));
                stackNumber.push(b);
                // 初始化位数变量
                intBit = 1;
                dotBit = 0;
            } else if (c == '+') {
                BigDecimal b1 = stackNumber.pop();
                BigDecimal b2 = stackNumber.pop();
                stackNumber.push(b2.add(b1));
            } else if (c == '-') {
                BigDecimal b1 = stackNumber.pop();
                BigDecimal b2 = stackNumber.pop();
                stackNumber.push(b2.subtract(b1));
            } else if (c == '*') {
                BigDecimal b1 = stackNumber.pop();
                BigDecimal b2 = stackNumber.pop();
                stackNumber.push(b2.multiply(b1));
            } else if (c == '/') {
                BigDecimal b1 = stackNumber.pop();
                BigDecimal b2 = stackNumber.pop();
                stackNumber.push(b2.divide(b1, MathContext.DECIMAL128));
            }
        }
        return stackNumber.pop();
    }

    /**
     * 判断传入的char是否为数字
     */
    private boolean isNumber(char c) {
        return (c >= 48 && c <= 57);
    }

}

 

简单的计算器 import java.awt.*; import java.awt.event.*; import javax.swing.*; public class MyCalculator extends Frame implements ActionListener { JTextField txt = new JTextField(""); StringBuffer copyBoard=new StringBuffer(20); private String cmd = "="; private double result = 0;// 运算结果 private boolean start = true; StringBuffer strs=new StringBuffer(); class Window { Window() { Frame help=new Frame("关于作者"); help.setBounds(400,200,200,200); help.setVisible(true); help.setResizable(false); help.addWindowListener(new WindowAdapter() //关闭窗口 { public void windowClosing(WindowEvent e) { ((Frame)e.getSource()).dispose(); } } ); TextArea title = new TextArea(" 软件125实训项目 一 制作:第二组 常志铭 朱靖 2013.5.10 ",10,8,TextArea.SCROLLBARS_NONE); title.setBounds(50,50,200,30); title.setEditable(false); help.add(title); } } MyCalculator() { this.setTitle("我的计算器"); this.setBounds(400,150,225,320); this.createMenu(); this.createMainPanel(); this.addWindowListener(new WindowAdapter() //关闭窗口 { public void windowClosing(WindowEvent e) { System.exit(0); } } ); this.setResizable(false); this.setVisible(true); } private void createMenu() { MenuBar bar = new MenuBar(); this.setMenuBar(bar); Menu EditMenu = new Menu("编辑(E)"); Menu helpMenu = new Menu("帮助(H)"); bar.add(EditMenu); bar.add(helpMenu); MenuItem copyItem = new MenuItem("复制"); copyItem.setShortcut(new MenuShortcut(KeyEvent.VK_C,false)); EditMenu.add(copyItem); copyItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { String temp = txt.getText().trim(); copyBoard.replace(0, copyBoard.length(), temp); } } ); MenuItem pasteItem = new MenuItem("粘帖"); pasteItem.setShortcut(new MenuShortcut(KeyEvent.VK_V,false)); EditMenu.add(pasteItem); pasteItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { txt.setText(copyBoard.toString()); result=(Double.parseDouble(copyBoard.toString())); } } ); MenuItem helpItem = new MenuItem("关于计算器"); helpItem.setShortcut(new MenuShortcut(KeyEvent.VK_H,false)); helpMenu.add(helpItem); helpItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { new Window(); } } ); } private void createMainPanel() { //整体面板 Panel Win = new Panel(null); Win.setSize(230, 330); Win.setVisible(true); //Win.setBackground(Color.black); this.add(Win); //显示 txt.setHorizontalAlignment(JTextField.RIGHT); txt.setBounds(5,5,210,50); txt.setFont(new java.awt.Font("Dialog", 1, 30)); txt.setEditable(false); Win.add(txt); //按键面板 Panel Butt = new Panel(null); Butt.setBounds(0, 50, 230, 280); //Butt.setBackground(Color.white); Butt.setVisible(true); Win.add(Butt); Button butx = new Button("C"); butx.setBounds(15,15,40,28); butx.addActionListener(this); butx.setFont(new java.awt.Font("Dialog", 1, 15)); Butt.add(butx); Button butz = new Button("←"); butz.setBounds(65,15,40,28); butz.setFont(new java.awt.Font("Dialog", 1, 20)); butz.addActionListener(this); Butt.add(butz); Button butcf = new Button("/"); butcf.setBounds(115,15,40,28); butcf.setFont(new java.awt.Font("Dialog", 0, 20)); butcf.addActionListener(this); Butt.add(butcf); Button butc = new Button("*"); butc.setBounds(165,15,40,28); butc.setFont(new java.awt.Font("Dialog", 1, 25)); butc.addActionListener(this); Butt.add(butc); Button but7 = new Button("7"); but7.setBounds(15,55,40,28); but7.setFont(new java.awt.Font("Dialog", 0, 15)); but7.addActionListener(this); Butt.add(but7); Button but8 = new Button("8"); but8.setBounds(65,55,40,28); but8.setFont(new java.awt.Font("Dialog", 0, 15)); but8.addActionListener(this); Butt.add(but8); Button but9 = new Button("9"); but9.setBounds(115,55,40,28); but9.setFont(new java.awt.Font("Dialog", 0, 15)); but9.addActionListener(this); Butt.add(but9); Button butjf = new Button("-"); butjf.setBounds(165,55,40,28); butjf.setFont(new java.awt.Font("Dialog", 0, 28)); butjf.addActionListener(this); Butt.add(butjf); Button but4 = new Button("4"); but4.setBounds(15,95,40,28); but4.setFont(new java.awt.Font("Dialog", 0, 15)); but4.addActionListener(this); Butt.add(but4); Button but5 = new Button("5"); but5.setBounds(65,95,40,28); but5.setFont(new java.awt.Font("Dialog", 0, 15)); but5.addActionListener(this); Butt.add(but5); Button but6 = new Button("6"); but6.setBounds(115,95,40,28); but6.setFont(new java.awt.Font("Dialog", 0, 15)); but6.addActionListener(this); Butt.add(but6); Button butj = new Button("+"); butj.setBounds(165,95,40,28); butj.setFont(new java.awt.Font("Dialog", 0, 20)); butj.addActionListener(this); Butt.add(butj); Button but1 = new Button("1"); but1.setBounds(15,135,40,28); but1.setFont(new java.awt.Font("Dialog", 0, 15)); but1.addActionListener(this); Butt.add(but1); Button but2 = new Button("2"); but2.setBounds(65,135,40,28); but2.setFont(new java.awt.Font("Dialog", 0, 15)); but2.addActionListener(this); Butt.add(but2); Button but3 = new Button("3"); but3.setBounds(115,135,40,28); but3.setFont(new java.awt.Font("Dialog", 0, 15)); but3.addActionListener(this); Butt.add(but3); Button bute = new Button("="); bute.setBounds(165,135,40,68); bute.setFont(new java.awt.Font("Dialog", 0, 25)); bute.addActionListener(this); Butt.add(bute); Button but0 = new Button("0"); but0.setBounds(15,175,90,28); but0.setFont(new java.awt.Font("Dialog", 0, 15)); but0.addActionListener(this); Butt.add(but0); Button butd = new Button("."); butd.setBounds(115,175,40,28); butd.setFont(new java.awt.Font("Dialog", 1, 25)); butd.addActionListener(this); Butt.add(butd); } public void actionPerformed(ActionEvent event) { String sf = event.getActionCommand(); if(sf.equals("9")||sf.equals("8")||sf.equals("7")||sf.equals("6")||sf.equals("5")||sf.equals("4")||sf.equals("3")||sf.equals("2")||sf.equals("1")||sf.equals("0")||sf.equals("C")||sf.equals("←")||sf.equals(".")) { String input = sf; if (start) { txt.setText(""); start = false; } if (input.equals("←")) { String str = txt.getText(); if (str.length() > 0) txt.setText(str.substring(0, str.length() - 1)); } else if (input.equals("C")) { txt.setText("0"); start = true; } else txt.setText(txt.getText() + input); } else { String command = sf; if (start) { cmd = command; } else { calculate(Double.parseDouble(txt.getText())); cmd = command; start = true; } } } public void calculate(double x) { if (cmd.equals("+")) result += x; else if (cmd.equals("-")) result -= x; else if (cmd.equals("*")) result *= x; else if (cmd.equals("/")) result /= x; else if (cmd.equals("=")) result = x; txt.setText("" + result); } public static void main (String[] args) { new MyCalculator(); } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值