kotlin
复制代码
package com.wis.leading.common.util;
import cn.hutool.core.util.NumberUtil;
import lombok.extern.slf4j.Slf4j;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Objects;
/**
* 此类封装了 {@link BigDecimal},提供了一套流畅(Fluent)的链式API,用于执行高精度的算术运算。旨在简化 {@link BigDecimal} 的使用。
* <p>
* 此类为可变对象(Mutable)!</b> 所有算术运算方法(如 {@link #add}, {@link #mul})都会修改其内部状态(即 {@code this} 对象)。
* 由于是可变对象,Num类本身不是线程安全的。 如果在多线程环境下共享同一个 Num 实例并进行写操作, 必须由外部进行同步控制(如使用 synchronized 或 Lock)
* <p>
* 意外的副作用 (Unintended Side Effects) 当一个 {@code Num} 对象被多个引用持有,通过任何一个引用修改其状态,都会影响到所有其他引用。
* <p>
* 严禁</b>将 {@code Num} 对象用作 {@link java.util.HashSet} 的元素或 {@link java.util.HashMap} 的键。
* 如果 {@code Num} 对象在放入集合后其值被修改,其 {@code hashCode()} 也会改变,导致集合无法再找到该对象。因为这些集合依赖对象的 {@code hashCode()} 和 {@code equals()}。
*/
@Slf4j
public final class Num {
private BigDecimal value;
private Num(BigDecimal value) {
this.value = value;
}
// 创建默认值
public static Num of(Number value) {
Objects.requireNonNull(value);
return new Num(NumberUtil.toBigDecimal(value));
}
// 创建默认值
public static Num of(Num value) {
return of(value.get());
}
// 创建默认值
public static Num of(String value) {
return of(new BigDecimal(value));
}
// 创建默认值等于0
public static Num zero() {
return of(BigDecimal.ZERO);
}
// 加
public Num add(Number... toAdd) {
for (Number item : toAdd) {
value = NumberUtil.add(value, item);
}
return this;
}
// 加
public Num add(Num... toAdd) {
for (Num item : toAdd) {
value = NumberUtil.add(value, item.get());
}
return this;
}
// 加
public Num add(String... toAdd) {
for (String item : toAdd) {
value = NumberUtil.add(value, new BigDecimal(item));
}
return this;
}
// 减
public Num sub(Number... toSubtract) {
for (Number item : toSubtract) {
value = NumberUtil.sub(value, item);
}
return this;
}
// 减
public Num sub(Num... toSubtract) {
for (Num item : toSubtract) {
value = NumberUtil.sub(value, item.get());
}
return this;
}
// 减
public Num sub(String... toSubtract) {
for (String item : toSubtract) {
value = NumberUtil.sub(value, new BigDecimal(item));
}
return this;
}
// 乘
public Num mul(Number... toMultiply) {
for (Number item : toMultiply) {
value = NumberUtil.mul(value, item);
}
return this;
}
// 乘
public Num mul(Num... toMultiply) {
for (Num item : toMultiply) {
value = NumberUtil.mul(value, item.get());
}
return this;
}
// 乘
public Num mul(String... toMultiply) {
for (String item : toMultiply) {
value = NumberUtil.mul(value, new BigDecimal(item));
}
return this;
}
// 除
public Num div(Number... toDivisor) {
for (Number item : toDivisor) {
value = NumberUtil.div(value, item);
}
return this;
}
// 除
public Num div(Num... toDivisor) {
for (Num item : toDivisor) {
value = NumberUtil.div(value, item.get());
}
return this;
}
// 除
public Num div(String... toDivisor) {
for (String item : toDivisor) {
value = NumberUtil.div(value, new BigDecimal(item));
}
return this;
}
// ============= 安全除法方法开始 =============
/**
* 安全除法 - 当除数为0时,返回0
*
* @param toDivisor 除数数组
* @return Num实例
*/
public Num divSafe(Number... toDivisor) {
for (Number item : toDivisor) {
if (item == null || Num.of(item).isZero()) {
log.warn("安全除法检测到无效除数 - 当前值:{}, 除数:{} (除数为null或0,将返回0)", this.value, item);
value = BigDecimal.ZERO;
return this;
}
value = NumberUtil.div(value, item);
}
return this;
}
/**
* 安全除法 - 当除数为0时,返回0
*
* @param toDivisor 除数数组
* @return Num实例
*/
public Num divSafe(Num... toDivisor) {
for (Num item : toDivisor) {
if (item == null || item.isZero()) {
log.warn("安全除法检测到无效除数 - 当前值:{}, 除数:{} (除数为null或0,将返回0)", this.value, item);
value = BigDecimal.ZERO;
return this;
}
value = NumberUtil.div(value, item.get());
}
return this;
}
/**
* 安全除法 - 当除数为0时,返回0
*
* @param toDivisor 除数数组
* @return Num实例
*/
public Num divSafe(String... toDivisor) {
for (String item : toDivisor) {
if (item == null || Num.of(item).isZero()) {
log.warn("安全除法检测到无效除数 - 当前值:{}, 除数:'{}' (除数为null或0,将返回0)", this.value, item);
value = BigDecimal.ZERO;
return this;
}
value = NumberUtil.div(value, new BigDecimal(item));
}
return this;
}
// ============= 安全除法方法结束 =============
/**
* 创建当前对象的副本(复制当前值)。
* 由于此类是可变的,通过副本可以保留当前状态,避免后续操作影响原始对象。
*
* @return 一个新的 Num 实例,其值与当前对象相同
*/
public Num copy() {
return Num.of(this.value);
}
// 获取结果
public BigDecimal get() {
return value;
}
// 获取结果 保留指定位小数
public BigDecimal get(int newScale) {
return get().setScale(newScale, RoundingMode.HALF_UP);
}
// 获取结果
public double getDoubleValue() {
return get().doubleValue();
}
// 获取结果 保留指定位小数
public double getDoubleValue(int newScale) {
return get(newScale).doubleValue();
}
// ============= 比较方法 =============
/**
* 是否为0(数值判断)
*/
public boolean isZero() {
return compareTo(BigDecimal.ZERO) == 0;
}
/**
* 大于
*
* @param other 要比较的数值
* @return 如果当前值大于参数数值,返回true;否则返回false
*/
public boolean gt(Number other) {
return compareTo(other) > 0;
}
/**
* 大于等于
*
* @param other 要比较的数值
* @return 如果当前值大于或等于参数数值,返回true;否则返回false
*/
public boolean gte(Number other) {
return compareTo(other) >= 0;
}
/**
* 小于
*
* @param other 要比较的数值
* @return 如果当前值小于参数数值,返回true;否则返回false
*/
public boolean lt(Number other) {
return compareTo(other) < 0;
}
/**
* 小于等于
*
* @param other 要比较的数值
* @return 如果当前值小于或等于参数数值,返回true;否则返回false
*/
public boolean lte(Number other) {
return compareTo(other) <= 0;
}
/**
* 等于
*
* @param other 要比较的数值
* @return 如果当前值等于参数数值,返回true;否则返回false
*/
public boolean eq(Number other) {
return compareTo(other) == 0;
}
/**
* 与另一个 Number 比较,返回 -1, 0, 1
*/
public int compareTo(Number other) {
Objects.requireNonNull(other, "比较对象不能为null");
return value.compareTo(NumberUtil.toBigDecimal(other));
}
@Override
public String toString() {
return value.toPlainString();
}
}