一.实现原理

  1. 获取计算表达式:用户点击button,显示器的值则push(button的值)。
    但push有要求:如果是括号或者运算符,则再其前后各+一个空格字符串,再push
  2. 创建一个储存运算符的集合(栈1)记作symbols,一个储存新的表达式的集合(栈2)记作newExpre。
  3. 对获取的表达式进行遍历,利用switch来进行判断,规则简单说明:
    I. 遇到'(',直接push到symbols
    II. 遇到‘)’ 从symbols最后一个开始,挨个pop,并push到newExpre中。直到遇到第一个‘(’结束。
    III. 遇到运算符:

    • 若symbols为空,则直接将该运算符push到symbols中
    • 比较其余symbols最后一个运算符的优先级,

       若前者低于后者,则将后者从symbols中pop,再push到
       newExpore中,重复此操作,一直到该运算符的优先级>symbols中
       最后一个运算符的优先级(或symbols为空),然后将前
       者push到symbols中。结束
    • 否则,直接将其push到symbols中.
 IV.  其它情况,直接push到newExpore中
  1. 遍历结束,将symbols从最后一个到第一个,挨个push到newExpre中。
  2. 计算,遍历newExpre:

    遇到运算符,根据该运算符 计算该运算符前两位的和/差/乘/除,结果存在该运算符前两位,在删除该运算符前一位,以及该运算符
    
注意: push表示集合的add()函数,pop表示集合的pollLast()函数。此处用的js数组相同功能的函数名

二.版本、工具等简单介绍

  1. 本文用到的是java-8.0.16版本,IDE用的软件IDEA
  2. 计算器继承了窗口类Frame,代码涉及JAVA的数据类型转换、字符串操作、集合linkedList操作、正则表达式、按钮自动生成、各种循环、
    判断用户简单的输入错误(例如少了括号),并自动修复功能等。
  3. 运算符号比较原则:"-"=="+" > "*"=="/"。

三.完整代码

package calculator;

import java.awt.*;
import java.awt.event.*;
import java.util.LinkedList;
import javax.swing.*;

public class calculator {
    public static void main(String[] args) { new CalculatorFrame("计算器"); }
}
//计算器的窗口
class CalculatorFrame extends Frame{
    private final int height=400;
    private final int width=700;
    private final int offset_x=20;
    private final int offset_y=40;
    private TextArea display,record;//显示屏与历史记录
    private String nullMessage="尚无历史记录...";
    //组件value
    private final String[] values={"(",")","C","Back","7","8","9","/","4","5","6","*","1","2","3","+","0",".","=","-"};

    //构造函数,本计算器入口
    public CalculatorFrame(String title){
        //this.setTitle(title);
        super(title);//设置计算器名字
        setMainFrame();//窗口基本设定
        setButton();//设置按钮
    }

    private void setMainFrame(){
        this.setLayout(null);//设置窗口布局为空
        this.setBounds(400,200,width,height);//设置显示位置,设置窗口大小
        this.setResizable(false);//窗口是否可调整大小
        this.setVisible(true);//窗口可视
        //关闭窗口监听事件
        this.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
        //设置显示屏
        display=new TextArea("0",8,52,3);//textarea
        display.setBounds(offset_x,offset_y,(int)(width*0.7),(int)(height*0.3));
        display.setEditable(false);
        display.setBackground(new Color(230, 230, 230));
        display.setFont(new Font("幼圆",Font.BOLD,15));
        this.add(display);
        //设置历史记录
        record=new TextArea(nullMessage,52,52,3);
        int left=offset_x+(int)(width*0.7);
        record.setBounds(left,offset_y,width-left,height-offset_y);
        record.setEditable(false);
        record.setBackground(new Color(230, 230, 230));
        record.setFont(new Font("幼圆",Font.TYPE1_FONT,10));
        //清空历史记录的按钮
        JButton delBtn=new JButton(new ImageIcon("src/images/del.png"));//给按钮增加背景图片
        delBtn.setBounds(width-40,height-40,20,20);//按钮大小,以及定位
        delBtn.setBackground(new Color(255,255,255));//设置一个默认的背景颜色
        delBtn.addMouseListener(new MouseAdapter(){
            @Override
            //鼠标点击,清空历史记录
            public void mousePressed(MouseEvent e){
                record.setText(nullMessage);
            }
        });
        this.add(delBtn);
        this.add(record);
    }
    private void setButton(){
        //显示屏
        int btn_width=(int)(width*0.7)/4;
        int btn_height=(int)(height*0.7-offset_y)/5;
        for(int i=0;i<values.length;i++){
            addButton(values[i],offset_x+btn_width*(i%4),5+offset_y+(int)(height*0.3)+btn_height*(int)(Math.floor(i/4)));
        }
    }

    private void addButton(String val,int x,int y){
        final Button btn=new Button(val);
        btn.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
        btn.setBounds(x,y,(int)(width*0.7)/4-5,(int)(height*0.7-offset_y)/5-5);
        btn.setFont(new Font("标楷体", Font.BOLD, 15));
        //增加点击事件
        btn.addMouseListener(new MouseAdapter(){
            @Override
            public void mousePressed(MouseEvent e) {
                final String[] exceptMessages={"NaN","Infinity"};
                Button Btn=(Button)e.getSource();//获取到点击的按钮对象
                String value=Btn.getLabel();//按钮的值
                String expression=display.getText();//获取显示屏的表达式
                int len=expression.length();//因为经常使用表达式长度,故在此提前声明
                switch (value){
                    case "C":
                        display.setText("0");
                        break;
                    case "Back":
                        boolean flag=false;
                        for(int i=0;i<exceptMessages.length;i++){
                            if(!expression.equals(exceptMessages[i])) continue;
                            flag=true;
                            break;
                        }
                        if(len==1) expression="0";
                        else if(flag==true){
                            //存在无穷,NaN等数据时
                            expression="0";
                        } else if(len>0 &&expression.lastIndexOf(" ")!=len-1 ){
                            expression=expression.substring(0,len-1);
                        }else if(len>0 &&expression.substring(len-4,len-3).matches("[0-9]+")) expression=expression.substring(0,len-3);
                        else if(len>0) expression=expression.substring(0,len-2);
                        display.setText(expression);
                        break;
                    case "+":
                    case "-":
                    case "*":
                    case "/":
                        if(expression.lastIndexOf(" ")==len-1 &&!expression.substring(len-2,len-1).equals("(")
                                &&!expression.substring(len-2,len-1).equals(")")){
                            expression=expression.substring(0,len-3);
                        }else if(len>1&& expression.substring(len-2,len-1).equals("(")){
                            expression+="0";
                        }
                        expression+=" "+value+" ";
                        display.setText(expression);
                        break;
                    case "(":
                    case ")":
                        if(value.equals(")") &&hasNums(expression,"(")<=hasNums(expression,")")) break;
                        else if(value.equals(")") &&expression.lastIndexOf(" ")==len-1 &&expression.lastIndexOf("(")!=len-2){
                            //形如 2+(5+ 的情况,自动加一个数
                            expression=autoAdd(expression);
                            len+=1;
                        }
                        if(expression.equals("0")) expression="";
                        else if(value=="(" &&expression.lastIndexOf(" ")!=len-1) expression+=" *";//5*(2+3)默认给个*号
                        if(expression.lastIndexOf(" ")==len-1) expression=expression.substring(0,len-1);//清除前面的空格
                        if(len>1 &&value.equals("(") && expression.lastIndexOf(")")==len-2){
                            //形如 (a+b)*(c+d) 中间加个*
                            expression+=" *";
                            len+=2;
                        }
                        expression+=" "+value+" ";
                        display.setText(expression);
                        break;
                    case ".":
                        if(expression.lastIndexOf(")")!=-1 && expression.lastIndexOf(")")==len-2) expression+="* 0"+value;//括号
                        else if(expression.lastIndexOf(" ")==len-1)expression+="0"+value;
                        else if(expression.lastIndexOf(".")!=-1 &&expression.lastIndexOf(".")>expression.lastIndexOf(" ")) break;//连续输入两个.
                        else expression+=value;
                        display.setText(expression);
                        break;
                    case "=":
                        if(hasNums(expression,"(")>hasNums(expression,")")){
                            //少了gapNum个括号
                            expression+=expression.lastIndexOf(" ")==len-1?"+ 0":" + 0";
                            int gapNum=hasNums(expression,"(")-hasNums(expression,")");
                            for(int i=0;i<gapNum;i++){
                                expression+=" ) ";
                            }
                        }
                        else if(expression.lastIndexOf(" ")==len-1 && expression.lastIndexOf(")")!=len-2){
                            //最后一个为运算符的时候,默认再表达式加个0或1
                            expression=autoAdd(expression);
                        }
                        cal(expression);
                        break;
                    default:
                        //exceptMessages
                        if(expression.substring(len-1).matches("[a-zA-Z]+")){
                            expression="0";
                        }
                        //数字
                        if(expression.equals("0")) expression="";
                        if(expression.lastIndexOf(" ")==len-1&&expression.lastIndexOf(")")==len-2) expression+="* ";
                        expression+=value;
                        display.setText(expression);
                }
            }
        });
        this.add(btn);
    }

    //计算
    private void cal(String str){
        //得到新的表达式
        LinkedList<String> expre=getNewExpre(str.split(" "));
        for(int i=0;i<expre.size();i++){
            System.out.print(expre.get(i)+",");
        }
        System.out.println();
        for(var i=0;i<expre.size();i++){
            var val=expre.get(i);
            switch(val){
                case "-":
                    expre.set(i-2,String.valueOf(Double.valueOf(expre.get(i-2).toString())-Double.valueOf(expre.get(i-1).toString())));
                    expre.remove(i-1);
                    expre.remove(i-1);
                    i-=2;
                    break;
                case "+":
                    expre.set(i-2,String.valueOf(Double.valueOf(expre.get(i-2).toString())+Double.valueOf(expre.get(i-1).toString())));
                    expre.remove(i-1);
                    expre.remove(i-1);
                    i-=2;
                    break;
                case "*":
                    expre.set(i-2,String.valueOf(Double.valueOf(expre.get(i-2).toString())*Double.valueOf(expre.get(i-1).toString())));
                    expre.remove(i-1);
                    expre.remove(i-1);
                    i-=2;
                    break;
                case "/":
                    expre.set(i-2,String.valueOf(Double.valueOf(expre.get(i-2).toString())/Double.valueOf(expre.get(i-1).toString())));
                    expre.remove(i-1);
                    expre.remove(i-1);
                    i-=2;
                    break;
                default:
                    break;
            }
        }
        String result=expre.get(0);

        display.setText(result);//归零
        //增加历史记录
        String recordStr=record.getText();
        if(recordStr.equals(nullMessage)) recordStr="";
        recordStr+=str+"="+result+"\n\n";
        record.setText(recordStr);
    }

    //0.0+5*(5+0.5)*0.5
    //得到新的表达式
    private LinkedList<String> getNewExpre(String[] expression){
        for(int i=0;i<expression.length;i++){
            System.out.print(expression[i]+",");
        }
        System.out.println();
        LinkedList<String> symbols=new LinkedList<>();//存放符号的栈
        LinkedList<String> newExpre=new LinkedList<>();//存放新的表达式的栈
        for (int i=0;i<expression.length;i++){
            String val=expression[i];
            if(val.equals("")) continue;
            System.out.println(symbols);
            System.out.println(newExpre);
            switch (val){
                case "(":symbols.add(val);break;
                case ")":
                    boolean isOk=true;
                    while(isOk){
                        String _symbol=symbols.pollLast();
                        if(_symbol.equals("(")) isOk=false;
                        else newExpre.add(_symbol);
                    };
                    break;
                case "+":
                case "-":
                case "*":
                case "/":
                    if(symbols.size()==0){
                        symbols.add(val);
                    } else if(compareSymbols(val,symbols.get(symbols.size()-1))) symbols.add(val);
                    else{
                        while (symbols.size()>0 && !compareSymbols(val,symbols.get(symbols.size()-1))){
                            newExpre.add(symbols.pollLast());//需要全部出栈,直到遇到优先级比自己小的.
                        }
                        symbols.add(val);
                    }
                    break;
                default:
                    newExpre.add(val);
            }
        }
        while(symbols.size()>0){
            newExpre.add(symbols.pollLast());
        }
        return newExpre;
    }

    //比较符号优先级
    private boolean compareSymbols(String newSymbol,String existSymbol){
        //只可能传入 +,-,*,/
        //false 表示要前者优先级更小或相等,符号栈最后一个元素需要出栈
        //true 表示前者优先级更高,符号直接进符号栈
        //遇到括号
        if(existSymbol.equals("(")) return true;
        //同优先级
        if(newSymbol.equals(existSymbol)) return false;
        else if((newSymbol.equals("*")||newSymbol.equals("/"))&&(existSymbol.equals("*")||existSymbol.equals("/"))) return false;
        else if((newSymbol.equals("+")||newSymbol.equals("-"))&&(existSymbol.equals("+")||existSymbol.equals("-"))) return false;
        //不同优先级
        else if((newSymbol.equals("-") ||newSymbol.equals("+")) &&(existSymbol.equals("*") || existSymbol.equals("/"))) return false;
        // 只剩下情况: 前者*或/ 遇到 后者+或*
        return true;
    }

    //判断str中有多少个val
    private int hasNums(String str,String val){
        int nums=0;
        while (str.indexOf(val)!=-1){
            nums+=1;
            str=str.substring(str.indexOf(val)+1);
        }
        return nums;
    }
    //表达式常见错误,自动再后边加0 或者1
    private String autoAdd(String expression){
        String symbol=expression.substring(expression.length()-2,expression.length()-1);
        switch (symbol){
            case "+":
            case "-":
                expression+="0";
                break;
            case "*":
            default:
                expression+="1";
        }
        return expression;
    }
}

邓奔成
6 声望4 粉丝