【一个数学计算工具类主要用来合计数据】

一个数学计算工具类

提供了一些常见的数学计算方法,包括将字符串转换为 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... 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... mappers) {
        try {
            T o = clazz.newInstance();
            for (IFunction 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... mappers) {
        try {
            T o = clazz.newInstance();
            for (IFunction 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 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;
    }

}

IFunction 自定义函数式接口,继承自Java8提供的{@link Function}接口,


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);
    }
}

你可能感兴趣的:(记录,Java,常用工具,java)