一直想实现一个计算类,但是苦于没有好的思路,最近闲来无事,理清思路,不服就干,话不多说,直接上代码。
相信各位都是编程界大神,代码思想就不用说了,懂的都懂。
package com.bbm.normaltool.utils;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Vector;
import java.util.function.BiFunction;
import lombok.Getter;
// 计算器:可以避免各个类型数字之间的运算之间的类型转换,并可以按照运算符优先级计算,如:
// 2*2 + 3*3 + 4*4 + 5*5 = 54
//
// @author BBM
public class NumberCalculator {
private BigDecimal value = BigDecimal.ZERO;
private final List<CalFactor> calFactors;
public NumberCalculator(Number newValue) {
this.calFactors = new Vector<>();
this.add(newValue);
}
public static NumberCalculator zero() {
return new NumberCalculator(0);
}
public static NumberCalculator one() {
return new NumberCalculator(1);
}
// 多个数连加:A+B+C
public NumberCalculator add(Number... numArray) {
Objects.requireNonNull(numArray);
BigDecimal temp = BigDecimal.ZERO;
for (Number number : numArray) {
temp = temp.add(new BigDecimal(number.toString()));
}
this.calFactors.add(new CalFactor(CalOperator.ADD, temp, null, null));
return this;
}
public NumberCalculator add(NumberCalculator... calculatorArray) {
Objects.requireNonNull(calculatorArray);
BigDecimal temp = BigDecimal.ZERO;
for (NumberCalculator calculator : calculatorArray) {
temp = temp.add(calculator.get());
}
this.calFactors.add(new CalFactor(CalOperator.ADD, temp, null, null));
return this;
}
// 多个数连减:-A-B-C
public NumberCalculator sub(Number... numArray) {
Objects.requireNonNull(numArray);
BigDecimal temp = BigDecimal.ZERO;
for (Number number : numArray) {
temp = temp.add(new BigDecimal(number.toString()));
}
this.calFactors.add(new CalFactor(CalOperator.SUB, temp, null, null));
return this;
}
public NumberCalculator sub(NumberCalculator... calculatorArray) {
Objects.requireNonNull(calculatorArray);
BigDecimal temp = BigDecimal.ZERO;
for (NumberCalculator calculator : calculatorArray) {
temp = temp.add(calculator.get());
}
this.calFactors.add(new CalFactor(CalOperator.SUB, temp, null, null));
return this;
}
// 多个数连乘:A*B*C
public NumberCalculator mul(Number... numArray) {
Objects.requireNonNull(numArray);
BigDecimal temp = BigDecimal.ONE;
for (Number number : numArray) {
temp = temp.multiply(new BigDecimal(number.toString()));
}
this.calFactors.add(new CalFactor(CalOperator.MUL, temp, null, null));
return this;
}
public NumberCalculator mul(NumberCalculator... calculatorArray) {
Objects.requireNonNull(calculatorArray);
BigDecimal temp = BigDecimal.ONE;
for (NumberCalculator calculator : calculatorArray) {
temp = temp.multiply(calculator.get());
}
this.calFactors.add(new CalFactor(CalOperator.MUL, temp, null, null));
return this;
}
public NumberCalculator div(Number num, int scale, RoundingMode roundMode) {
Objects.requireNonNull(num);
this.calFactors.add(new CalFactor(CalOperator.DIV, new BigDecimal(num.toString()), scale, roundMode));
return this;
}
public NumberCalculator div(NumberCalculator otherCalculator, int scale, RoundingMode roundMode) {
Objects.requireNonNull(otherCalculator);
this.calFactors.add(new CalFactor(CalOperator.DIV, otherCalculator.get(), scale, roundMode));
return this;
}
// 利用现有的value值和calFactors里面的数据进行计算,
// 得出新的value值,并将calFactors清空,避免重复计算。
public NumberCalculator cal() {
if (!this.calFactors.isEmpty()) {
BigDecimal newValue = this.value;
if (this.calFactors.size() == 1) {
newValue = this.calFactors.get(0).cal(newValue);
} else {
// 简化计算过程,将乘除运算改成简单加减运算:
// 输入:2+2*3*4-5/8
// tempOptFactors[0]=[+,0]
// tempOptFactors[1]=[+,2]
// tempOptFactors[1]=[+,2*3*4=24]
// tempOptFactors[1]=[-,5/8=0.625]
// 最终变成 ==》
// tempOptFactors[0]=[+,0]
// tempOptFactors[1]=[+,2]
// tempOptFactors[1]=[+,24]
// tempOptFactors[1]=[-,0.625]
List<CalFactor> tempCalFactors = new ArrayList<>();
tempCalFactors.add(new CalFactor(CalOperator.ADD, newValue, null, null));
CalFactor tempCalFactor = null;
BigDecimal tmp;
for (int i = 1; i < this.calFactors.size(); i++) {
CalFactor calFactor = this.calFactors.get(i);
CalFactor lastCalFactor = this.calFactors.get(i - 1);
if (calFactor.getCalOperator() == CalOperator.ADD
|| calFactor.getCalOperator() == CalOperator.SUB) {
if (tempCalFactor == null) {
tempCalFactors.add(lastCalFactor);
} else {
tempCalFactors.add(tempCalFactor);
}
if (i == this.calFactors.size() - 1) {
tempCalFactors.add(calFactor);
}
tempCalFactor = null;
} else {
if (tempCalFactor == null) {
tempCalFactor = lastCalFactor;
}
tmp = calFactor.cal(tempCalFactor.getNum());
tempCalFactor.setNum(tmp);
}
}
if (tempCalFactor != null) {
tempCalFactors.add(tempCalFactor);
}
newValue = BigDecimal.ZERO;
for (CalFactor calFactor : tempCalFactors) {
newValue = calFactor.cal(newValue);
}
}
this.calFactors.clear();
this.value = newValue;
}
return this;
}
public NumberCalculator setScale(int scale, RoundingMode roundMode) {
this.value = this.cal().value.setScale(scale, roundMode);
return this;
}
public BigDecimal get() {
return this.cal().value;
}
public BigDecimal get(int scale, RoundingMode roundMode) {
return this.setScale(scale, roundMode).value;
}
public double getDoubleValue() {
return this.get().doubleValue();
}
public long getLongValue() {
return this.get().longValue();
}
public int getIntValue() {
return this.get().intValue();
}
public float getFloatValue() {
return this.get().floatValue();
}
public short getShortValue() {
return this.get().shortValue();
}
public byte getByteValue() {
return this.get().byteValue();
}
enum CalOperator {// 运算符
ADD("+", (b, c) -> b.add(c.getNum())),
SUB("-", (b, c) -> b.subtract(c.getNum())),
MUL("*", (b, c) -> b.multiply(c.getNum())),
DIV("/", (b, c) -> b.divide(c.getNum(), c.getScale(), c.getRoundMode()));
private final String code;
private final BiFunction<BigDecimal, CalFactor, BigDecimal> function;
CalOperator(String newCode, BiFunction<BigDecimal, CalFactor, BigDecimal> newFunction) {
this.code = newCode;
this.function = newFunction;
}
BigDecimal cal(BigDecimal b, CalFactor c) {
return this.function.apply(b, c);
}
}
@Getter
static final class CalFactor {// 每个计算元素/计算因子
private final CalOperator calOperator;
private BigDecimal num;
private final Integer scale;// 仅除法时生效
private final RoundingMode roundMode;// 仅除法时生效
CalFactor(CalOperator newCalOperator, BigDecimal newNum, Integer newScale, RoundingMode newRoundMode) {
this.calOperator = newCalOperator;
this.num = newNum;
this.scale = newScale;
this.roundMode = newRoundMode;
}
public BigDecimal cal(BigDecimal b) {
return this.calOperator.cal(b, this);
}
public void setNum(BigDecimal newNum) {
this.num = newNum;
}
}
}
执行一把看看结果:
public static void main(String[] args) {
// 2*2 + 3*3 + 4*4 + 5*5 = 54
NumberCalculator cal = new NumberCalculator(0);
for (int i = 2; i <= 5; i++) {
cal.add(i).mul(i);
}
System.out.println(cal.get());
// ((((2*2)+3)*3+4)*4+5)*5=525
NumberCalculator cal2 = new NumberCalculator(0);
for (int i = 2; i <= 5; i++) {
cal2.add(i).cal().mul(i);
}
System.out.println(cal2.get());
// (1+2)*(3+4)*(5+6)*(7+8)=3465
NumberCalculator cal3 =
new NumberCalculator(1).add(2)
.cal()
.mul(new NumberCalculator(3).add(4))
.mul(new NumberCalculator(5).add(6))
.mul(new NumberCalculator(7).add(8));
System.out.println(cal3.get());
// (4+4+4+4)*(5+5+5+5)*(6+6+6+6)=7680
NumberCalculator cal4 =
new NumberCalculator(0).add(4, 4, 4, 4)
.cal()
.mul(new NumberCalculator(0).add(5, 5, 5, 5))
.mul(new NumberCalculator(0).add(6, 6, 6, 6));
System.out.println(cal4.get());
// (4+4+4+4)*(5+5+5+5)*(6+6+6+6)=7680
NumberCalculator cal5 =
new NumberCalculator(1).mul(
new NumberCalculator(0).add(4, 4, 4, 4),
new NumberCalculator(0).add(5, 5, 5, 5),
new NumberCalculator(0).add(6, 6, 6, 6));
System.out.println(cal5.get());
// 1-2-3-4-5-6-7-8-9-10
NumberCalculator cal6 = new NumberCalculator(1).sub(2, 3, 4, 5, 6, 7, 8, 9, 10);
System.out.println(cal6.get());
// ((1+2*3*4)/5+44)/7
System.out.println(
new NumberCalculator(1).add(2)
.mul(3, 4)
.cal()
.div(5, 4, RoundingMode.HALF_UP)
.add(44)
.cal()
.div(7, 4, RoundingMode.HALF_UP)
.get());
}
输出结果如下:
从代码执行结果上看,简直就是YYDS,而且只要是继承了Number类的数字类型,都可以直接传入,有效避免了做类型转换,输出结果支持7种数据类型,保证够你使。