提供了一些常见的数学计算方法,包括将字符串转换为 double 类型、计算多个字符串形式的 double 值之和、将任意数量的浮点数相加等。同时,该类还提供了针对字符串的数值型数据求和的方法,可以通过传入一个对象集合和一组函数,自动计算出集合中各个对象在这些函数上的和并返回一个新的对象。
str2Double(String doubleValue):将字符串转换为 double 类型。
getDoubleSum(String... doubleValues):计算多个字符串形式的 double 值之和。
getDoubleSumStr(String... doubleValues):计算多个字符串形式的 double 值之和,并将结果转换为字符串形式返回。
getDoubleMulStr(String... doubles):将任意数量的浮点数相加,并返回其字符串形式。
addDouble(double... values):将任意数量的浮点数相加。
addDoubleByParallel(double... values):将任意数量的浮点数相加(并行计算)。
getDouble(String str):将字符串形式的浮点数转换为 double 类型。
getDouble2String(double num):将 double 类型的数转换为字符串形式。
getDoubleMulStr(double... doubles):将任意数量的浮点数相加,并返回其字符串形式。
mapperSumString(Class clazz, List list, IFunction super T, ? extends String>... mappers):针对字符串的数值型数据求和。
等等
import com.lfsun.common.config.IFunction;
import java.lang.reflect.Method;
import java.text.DecimalFormat;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.StringJoiner;
import java.util.stream.Collectors;
import java.util.stream.DoubleStream;
/**
* 数学计算工具类
*/
public class MyMathUtil {
private static final DecimalFormat DECIMAL_FORMAT;
static {
DECIMAL_FORMAT = new DecimalFormat("#.00");
}
/**
* 将字符串转换为 double 类型
*
* @param doubleValue 字符串形式的 double 值
* @return 转换后的 double 值
*/
public static Double str2Double(String doubleValue) {
return Double.valueOf(doubleValue); // 直接使用 Double.valueOf 方法转换字符串
}
/**
* 计算多个字符串形式的 double 值之和
*
* @param doubleValues 多个字符串形式的 double 值
* @return 计算后的 double 值
*/
public static double getDoubleSum(String... doubleValues) {
double sum = 0.0;
for (String doubleValue : doubleValues) { // 遍历所有输入的字符串形式的 double 值
sum += Double.parseDouble(doubleValue); // 将字符串形式的 double 值转换为 double 类型并累加到 sum 中
}
return sum;
}
/**
* 计算多个字符串形式的 double 值之和,并将结果转换为字符串形式返回
*
* @param doubleValues 多个字符串形式的 double 值
* @return 计算后的字符串形式的 double 值
*/
public static String getDoubleSumStr(String... doubleValues) {
double sum = getDoubleSum(doubleValues); // 调用 getDoubleSum 方法计算多个字符串形式的 double 值之和
return Double.toString(sum); // 将 double 值转换为字符串形式并返回
}
/**
* 将任意数量的浮点数相加,并返回其字符串形式
*
* @param doubles 要相加的浮点数
* @return 浮点数相加的结果的字符串形式
*/
public static String getDoubleMulStr(String... doubles) {
double sum = 0;
for (String str : doubles) {
sum += getDouble(str);
}
return getDouble2String(sum);
}
/**
* 将任意数量的浮点数相加
*
* @param values 要相加的浮点数
* @return 浮点数相加的结果
*/
public static double addDouble(double... values) {
double sum = 0;
for (double value : values) {
sum += value;
}
return sum;
}
/**
* 将任意数量的浮点数相加
*
* @param values 要相加的浮点数
* @return 浮点数相加的结果
*/
public static double addDoubleByParallel(double... values) {
return Arrays.stream(values).parallel().sum();
}
/**
* 将字符串形式的浮点数转换为 double 类型
*
* @param str 字符串形式的浮点数
* @return 对应的 double 类型
*/
public static double getDouble(String str) {
return Double.parseDouble(str);
}
/**
* 将 double 类型的数转换为字符串形式
*
* @param num 要转换的 double 类型的数
* @return 对应的字符串形式
*/
public static String getDouble2String(double num) {
return String.valueOf(num);
}
/**
* 将任意数量的浮点数相加,并返回其字符串形式
*
* @param doubles 要相加的浮点数
* @return 浮点数相加的结果的字符串形式
*/
public static String getDoubleMulStr(double... doubles) {
double sum = DoubleStream.of(doubles).sum();
StringJoiner joiner = new StringJoiner(" + ", "", " = " + DECIMAL_FORMAT.format(sum));
DoubleStream.of(doubles).forEach(d -> joiner.add(DECIMAL_FORMAT.format(d)));
return joiner.toString();
}
/**
* 针对字符串的数值型
* 利用反射形成合计数据
* 通过clazz.newInstance()构造合计数据行
* 循环处理每一个IFunction,可以看出1、2出代码就是上方获取aa、bb累计
* 通过get方法获取对应的set方法
* 给第一步构造的数据执行set方法赋值
*/
public static T mapperSumString(Class clazz, List list, IFunction super T, ? extends String>... mappers) {
try {
T o = clazz.newInstance();
for (IFunction super T, ? extends String> mapper : mappers) {
List data = list.stream()
.map(mapper)
.filter(Objects::nonNull)
.collect(Collectors.toList());
String add = getDouble2String(data.stream().mapToDouble(MyMathUtil::getDouble).sum());
String setMethod = getSetMethodName(mapper);
Method method = clazz.getMethod(setMethod, String.class);
method.invoke(o, add);
}
return o;
} catch (Exception e) {
throw new ServiceException("数据异常!", e);
}
}
/**
* 针对数值型
*/
public static T mapperSum(Class clazz, List list, IFunction super T, ? extends Double>... mappers) {
try {
T o = clazz.newInstance();
for (IFunction super T, ? extends Double> mapper : mappers) {
List data = list.stream()
.map(mapper)
.filter(Objects::nonNull)
.collect(Collectors.toList());
Double add = data.stream().mapToDouble(x -> x).sum();
String setMethod = getSetMethodName(mapper);
Method method = clazz.getMethod(setMethod, Double.class);
method.invoke(o, add);
}
return o;
} catch (Exception e) {
throw new ServiceException("数据异常!", e);
}
}
/**
* 获取字段的 set 方法名称,用于反射调用
*
* @param func 带有 get 方法的字段
* @param 字段所属类的类型
* @param 字段类型
* @return 字段的 set 方法名称
*/
private static String getSetMethodName(IFunction super T, ? extends R> func) {
String implMethodName = func.getImplMethodName(); // 获取 get 方法名称
String substring = implMethodName.substring(3); // 去掉 get 前缀,得到字段名称
return "set" + substring; // 拼接 set 方法名称
}
/**
* 判断数值是不是偶数
*
* @param x
* @return
*/
public static boolean isEven(int x) {
return (x % 2) == 0; // 使用取模运算符更直观,避免魔数
}
/**
* 判断数值是不是奇数
*
* @param x
* @return
*/
public static boolean isOdd(int x) {
return (x % 2) == 1; // 同上
}
/**
* 获取最大值
*
* @param values
* @return
*/
public static double maxNumber(double... values) {
double maxNumber = Double.NEGATIVE_INFINITY; // 使用Double.NEGATIVE_INFINITY代替Double.MIN_VALUE,避免错误
for (double v : values) {
if (v > maxNumber) {
maxNumber = v;
}
}
return maxNumber;
}
/**
* 获取最小值
*
* @param values
* @return
*/
public static double minNumber(double... values) {
double minNumber = Double.POSITIVE_INFINITY; // 使用Double.POSITIVE_INFINITY代替Double.MAX_VALUE,避免错误
for (double v : values) {
if (v < minNumber) {
minNumber = v;
}
}
return minNumber;
}
}
import java.io.Serializable;
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Method;
import java.util.function.Function;
/**
* 自定义函数式接口,继承自Java8提供的{@link Function}接口,
*
* 并且扩展了获取Lambda表达式序列化对象的方法。
*
* @author Administrator
* @param 输入类型
* @param 输出类型
*/
@FunctionalInterface
public interface IFunction extends Function, Serializable {
/**
* 默认方法,用于获取Lambda表达式的序列化对象。
*
* @return Lambda表达式的序列化对象
* @throws IllegalArgumentException 获取序列化对象失败时抛出异常
*/
default SerializedLambda getSerializedLambda() throws IllegalArgumentException {
try {
Method method = this.getClass().getDeclaredMethod("writeReplace");
method.setAccessible(true);
return (SerializedLambda) method.invoke(this);
} catch (Exception e) {
throw new IllegalArgumentException("获取序列化对象失败", e);
}
}
/**
* 获取Lambda表达式的实现类名。
*
* @return Lambda表达式的实现类名
*/
default String getImplClass() {
return getSerializedLambda().getImplClass();
}
/**
* 获取Lambda表达式的实现方法名。
*
* @return Lambda表达式的实现方法名
*/
default String getImplMethodName() {
return getSerializedLambda().getImplMethodName();
}
}
import com.lfsun.main.util.MyMathUtil;
import com.lfsun.model.entity.UserSDDD;
import com.lfsun.model.entity.UserSSSS;
import org.junit.Assert;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
public class MyMathUtilTest {
@Test
void testStr2Double() {
assertEquals(1.0, MyMathUtil.str2Double("1.0"));
assertEquals(-0.5, MyMathUtil.str2Double("-0.5"));
assertThrows(NumberFormatException.class, () -> MyMathUtil.str2Double("not a number"));
}
@Test
void testGetDoubleSum() {
assertEquals(3.0, MyMathUtil.getDoubleSum("1.0", "2.0"));
assertEquals(0.0, MyMathUtil.getDoubleSum("1.0", "-1.0"));
assertEquals(0.0, MyMathUtil.getDoubleSum("0.0"));
assertEquals(0.0, MyMathUtil.getDoubleSum());
}
@Test
void testGetDoubleSumStr() {
assertEquals("3.0", MyMathUtil.getDoubleSumStr("1.0", "2.0"));
assertEquals("0.0", MyMathUtil.getDoubleSumStr("1.0", "-1.0"));
assertEquals("0.0", MyMathUtil.getDoubleSumStr("0.0"));
assertEquals("0.0", MyMathUtil.getDoubleSumStr());
}
@Test
void testAddDouble() {
assertEquals(3.0, MyMathUtil.addDouble(1.0, 2.0));
assertEquals(0.0, MyMathUtil.addDouble(1.0, -1.0));
assertEquals(0.0, MyMathUtil.addDouble(0.0));
assertEquals(0.0, MyMathUtil.addDouble());
}
@Test
void testAddDoubleByParallel() {
assertEquals(3.0, MyMathUtil.addDoubleByParallel(1.0, 2.0));
assertEquals(0.0, MyMathUtil.addDoubleByParallel(1.0, -1.0));
assertEquals(0.0, MyMathUtil.addDoubleByParallel(0.0));
assertEquals(0.0, MyMathUtil.addDoubleByParallel());
}
@Test
void testGetDouble() {
assertEquals(1.0, MyMathUtil.getDouble("1.0"));
assertEquals(-0.5, MyMathUtil.getDouble("-0.5"));
assertThrows(NumberFormatException.class, () -> MyMathUtil.getDouble("not a number"));
}
@Test
void testGetDouble2String() {
assertEquals("1.0", MyMathUtil.getDouble2String(1.0));
assertEquals("-0.5", MyMathUtil.getDouble2String(-0.5));
}
@Test
public void testGetDoubleMulStr() {
Assert.assertEquals("2.00 + 3.14 + 5.80 = 10.94", MyMathUtil.getDoubleMulStr(2, 3.14, 5.8));
Assert.assertEquals("0.10 + 0.20 + 0.30 + 0.40 = 1.00", MyMathUtil.getDoubleMulStr(0.1, 0.2, 0.3, 0.4));
Assert.assertEquals("111.10 + 222.20 + 333.30 + 444.40 = 1111.00", MyMathUtil.getDoubleMulStr(111.10, 222.20, 333.30, 444.40));
}
@Test
public void testMapperSumString() {
List list = new ArrayList<>();
list.add(new UserSSSS("obj1", "1.11", "2.22", null));
list.add(new UserSSSS("obj2", "3.33", "4.44", "5.55"));
UserSSSS sum = MyMathUtil.mapperSumString(UserSSSS.class, list, UserSSSS::getStr1, UserSSSS::getStr2, UserSSSS::getStr3);
Assert.assertEquals("4.44", sum.getStr1());
Assert.assertEquals("6.66", sum.getStr2());
Assert.assertEquals("5.55", sum.getStr3());
}
@Test
public void testMapperSum() {
List list = new ArrayList<>();
list.add(new UserSDDD("obj1", 1.1, 2.2, null));
list.add(new UserSDDD("obj2", 3.3, 4.4, 5.5));
UserSDDD sum = MyMathUtil.mapperSum(UserSDDD.class, list, UserSDDD::getD1, UserSDDD::getD2, UserSDDD::getD3);
Assert.assertEquals(4.4, sum.getD1(), 0.001);
Assert.assertEquals(6.6, sum.getD2(), 0.001);
Assert.assertEquals(5.5, sum.getD3(), 0.001);
}
@Test
public void testIsEven() {
Assert.assertTrue(MyMathUtil.isEven(2));
Assert.assertTrue(MyMathUtil.isEven(0));
Assert.assertFalse(MyMathUtil.isEven(1));
Assert.assertFalse(MyMathUtil.isEven(-1));
}
@Test
public void testIsOdd() {
Assert.assertFalse(MyMathUtil.isOdd(2));
Assert.assertFalse(MyMathUtil.isOdd(0));
Assert.assertTrue(MyMathUtil.isOdd(1));
Assert.assertFalse(MyMathUtil.isOdd(-1));
}
@Test
public void testMaxNumber() {
Assert.assertEquals(5.5, MyMathUtil.maxNumber(1.1, 2.2, 3.3, 5.5, -1.1), 0.001);
Assert.assertEquals(Double.NEGATIVE_INFINITY, MyMathUtil.maxNumber(), 0.001);
}
@Test
public void testMinNumber() {
Assert.assertEquals(-1.1, MyMathUtil.minNumber(1.1, 2.2, 3.3, 5.5, -1.1), 0.001);
Assert.assertEquals(Double.POSITIVE_INFINITY, MyMathUtil.minNumber(), 0.001);
}
}