Java制作计算器主要需要考虑的是加减乘除的运算顺序的优先级,
比如:
20-2-1.7*4/5-4*2
需要先计算1.7*4/5,
再计算4 *2,
最后从左往右计算加减。
网上其他的一些计算器都是运用队列和栈,中缀表达式转为后缀表达式等操作来进行的,比如:
Java编写简单计算器–实现篇
这种写法比较复杂不易理解。
所以自己用递归的思想写了个计算器:
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Test {
public static void main(String[] args) throws IOException {
System.out.println("请输入要计算的运算:");
Scanner scanner = new Scanner(System.in);
System.out.println(saveNumber_Symbol(scanner.next()));
}
/**
* 分割字符串存储运算符和数字分别到calcuStrList和numberList
*
* @param str 输入的计算表达式
*/
public static String saveNumber_Symbol(String str) {
String errorTip = "您的输入有误,请检查输入是否有误";
if (str.contains("$")) {
return errorTip;
}
str += "$"; //加上"$"用于获取分割最后一个数字
char[] strChar = str.toCharArray();
List<String> calcuStrList = new ArrayList<>();//存储运算符号
List<String> numberList = new ArrayList<>();//存储数字
StringBuilder buff = new StringBuilder();
int i = 0;
for (char ch : strChar) {
String number = buff.toString();
if (ch == '+' || ch == '-' || ch == '*' || ch == '/') {
calcuStrList.add(String.valueOf(ch));
boolean errorNumber = isErrorNumber(number);
if (errorNumber) {
return errorTip;
}
numberList.add(number);
buff.delete(0, buff.length());
} else if (ch == '$') {//判断是不是最后一个数
boolean errorNumber = isErrorNumber(number);
if (errorNumber) {
return errorTip;
}
numberList.add(buff.toString());
} else {
buff.append(ch);
}
}
return calculationOrder(calcuStrList, numberList);
}
/**
* 检查该输入的数字是否是错误的数字(即是否含有特殊字符)
*
* @param number 数字
*/
public static boolean isErrorNumber(String number) {
if (number.startsWith(".")) {
return true;
}
char[] ch = number.toCharArray();
for (char c : ch) {
int i = (int) c;
if ((i >= 45 && i <= 57) || (i >= 42 && i <= 43)) {
continue;
} else {
return true;
}
}
try {
Float.valueOf(number);
} catch (NumberFormatException e) {
return true;
}
return false;
}
/**
* 控制加减乘除的运算优先级顺序
*
* @param calcuStr 保存所有的运算符
* @param number 保存所有的数字
*/
public static String calculationOrder(List<String> calcuStr, List<String> number) {
if (calcuStr.size() > 0) {
int multiply = calcuStr.indexOf("*");
int except = calcuStr.indexOf("/");
//除在前乘在后,或有除无乘,则先算除
if ((-1 != multiply && -1 != except && except < multiply) || (calcuStr.contains("/") && !calcuStr.contains("*"))) {
calcuResult("/", calcuStr, number);
}
//乘在前除在后,或有乘无除,先算乘
if ((-1 != multiply && -1 != except && multiply < except) || (calcuStr.contains("*") && !calcuStr.contains("/"))) {
calcuResult("*", calcuStr, number);
}
//无乘除只有加减,则从左往右计算
if (calcuStr.size() > 0) {
calcuResult(calcuStr.get(0), calcuStr, number);
}
}
return number.get(0);
}
/**
* 通过symbol找到运算符在calcuStr出现的位置,根据位置在number中找到符号前后的两个数进行计算
*
* @param calcuStr 保存所有的运算符
* @param number 保存所有的数字
*/
public static String calcuResult(String symbol, List<String> calcuStr, List<String> number) {
int position = calcuStr.indexOf(symbol);
BigDecimal a = new BigDecimal(number.get(position));
BigDecimal b = new BigDecimal(number.get(position + 1));
String calculateNumber = "";
switch (symbol) {
case "-":
calculateNumber = String.valueOf(a.subtract(b));
break;
case "*":
calculateNumber = String.valueOf(a.multiply(b));
break;
case "/":
//除法四舍五入保留两位小数
calculateNumber = String.valueOf(a.divide(b, 2, RoundingMode.HALF_UP));
break;
default:
calculateNumber = String.valueOf(a.add(b));
}
number.set(position, calculateNumber);//两个数运算完后将计算结果覆盖到第一个数的位置
calcuStr.remove(position);//每用完一个运算符就删除该运算符
number.remove(position + 1);//两个数运算完后删除后面的数
return calculationOrder(calcuStr, number);
}
}
测试结果:
请输入要计算的四则运算:
30-4*7/2+2
18.00
关于递归,以
30-4*7/2+2
为例:
不断递归先运算完乘除,再从左向右按顺序计算加减。