Java range工具类(自定义)

在python中存在range函数,效果如下:
在这里插入图片描述
即可指定range的step,而在Java中IntStream只能指定start, end,而正好项目中需要使用该特性,且需要对列表进行拆分,故实现了如下工具类。

工具代码

import com.mx.xxx.base.MsgRuntimeException;

import java.util.Collection;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * range工具类
 *
 * @Author luohq
 * @Date 2020/08/31
 */
public final class RangeUtils {

    private RangeUtils() {
    }

    /**
     * 整数相除,对商进行向上取整
     *
     * @param dividend
     * @param divisor
     * @return
     */
    private static Integer ceilDivide(Integer dividend, Integer divisor) {
        int remainder = dividend % divisor;
        int quotient = dividend / divisor;
        int ceilQuotient = (0 == remainder ? quotient : quotient + 1);
        return ceilQuotient;
    }

    /**
     * 生成整数的rangeStream<br/>
     * 注:要求start < endExlude,且step > 0 <br/>
     * <p>
     * 例:
     * <ul>
     *     <li>rangeStream(0, 10, 2) ==> 0, 2, 4, 6, 8</li>
     *     <li>rangeStream(0, 10, 3) ==> 0, 3, 6, 9</li>
     *     <li>rangeStream(0, 10, 4) ==> 0, 4, 8</li>
     * </ul>
     *
     * @param start      起始边界
     * @param endExclude 结束边界(不包括)
     * @param step       步长
     * @return Stream&lt;Integer&gt;
     */
    public static Stream<Integer> rangeStream(Integer start, Integer endExclude, Integer step) {
        //校验参数
        checkStartAndEndIndex(start, endExclude, step);
        //计算批次数量
        Integer stepCount = ceilDivide((endExclude - start), step);
        //生成range stream
        return IntStream.range(0, stepCount).mapToObj(stepIndex -> stepIndex * step);
    }

    /**
     * 生成整数的rangeStream且返回具体索引(stepIndex, startIndex, endIndex)<br/>
     * 注:要求start < endExlude,且step > 0 <br/>
     * <p>
     * 例:
     * <ul>
     *     <li>rangeStream(0, 10, 2) ==> (0,0,1), (1,2,3), (2,4,5), (3,6,7), (4,8,9)</li>
     *     <li>rangeStream(0, 10, 3) ==> (0,0,2), (1,3,5), (2,6,8), (3,9,9)</li>
     *     <li>rangeStream(0, 10, 4) ==> (0,0,3), (1,4,7), (2,8,9)</li>
     * </ul>
     *
     * @param start      起始边界
     * @param endExclude 结束边界(不包括)
     * @param step       步长
     * @return Stream&lt;RangeIndex(stepIndex, startIndex, endIndex)&gt;
     */
    public static Stream<RangeIndex> rangeStreamWithIndex(Integer start, Integer endExclude, Integer step) {
        //校验参数
        checkStartAndEndIndex(start, endExclude, step);
        //计算批次数量
        Integer stepCount = ceilDivide((endExclude - start), step);
        //生成range stream
        return IntStream.range(0, stepCount).mapToObj(stepIndex -> {
            Integer stepStartIndex = stepIndex * step;
            Integer stepEndIndex = Math.min(stepStartIndex + step, endExclude);
            return new RangeIndex(stepIndex, stepStartIndex, stepEndIndex);
        });
    }

    /**
     * 执行list的rangeStream,并同过consumer处理集合拆分后的子range集合<br/>
     *
     * @param list               列表集合
     * @param start              起始边界
     * @param endExclude         结束边界(不包括)
     * @param step               步长
     * @param handlerRangeStream 处理每个range的consumer
     * @param <T>
     */
    public static <T extends List> void rangeStream(T list, Integer start, Integer endExclude, Integer step, Consumer<T> handlerRangeStream) {
        //校验集合
        checkCollection(list);
        //校验非空
        checkEmpty(handlerRangeStream, "consumer");
        //执行rangeStream
        rangeStreamWithIndex(start, endExclude, step).forEach(rangeIndex -> {
            T subList = (T) list.subList(rangeIndex.getStartIndex(), rangeIndex.getStopIndexExclude());
            handlerRangeStream.accept(subList);
        });
    }

    /**
     * 执行list的rangeStream,并同过biConsumer处理集合拆分后的子range集合,同时返回具体索引(stepIndex, startIndex, endIndex)<br/>
     *
     * @param list               列表集合
     * @param start              起始边界
     * @param endExclude         结束边界(不包括)
     * @param step               步长
     * @param handlerRangeStream 处理每个range的biConsumer
     * @param <T>
     */
    public static <T extends List> void rangeStream(T list, Integer start, Integer endExclude, Integer step, BiConsumer<RangeIndex, T> handlerRangeStream) {
        //校验集合
        checkCollection(list);
        //校验非空
        checkEmpty(handlerRangeStream, "consumer");
        //执行rangeStream
        rangeStreamWithIndex(start, endExclude, step).forEach(rangeIndex -> {
            T subList = (T) list.subList(rangeIndex.getStartIndex(), rangeIndex.getStopIndexExclude());
            handlerRangeStream.accept(rangeIndex, subList);
        });
    }

    /**
     * 执行list的rangeStream,并同过consumer处理子range集合<br/>
     * 注:start=0, endExclue=list.size()
     *
     * @param list               列表集合
     * @param step               步长
     * @param handlerRangeStream 处理每个range的consumer
     * @param <T>
     */
    public static <T extends List> void rangeStream(T list, Integer step, Consumer<T> handlerRangeStream) {
        //校验集合
        checkCollection(list);
        //执行rangeStream(遍历整个list)
        rangeStream(list, 0, list.size(), step, handlerRangeStream);
    }

    /**
     * 执行list的rangeStream,并同过biConsumer处理子range集合,且返回具体索引(stepIndex, startIndex, endIndex)<br/>
     * 注:start=0, endExclue=list.size()
     *
     * @param list               列表集合
     * @param step               步长
     * @param handlerRangeStream 处理每个range的biConsumer
     * @param <T>
     */
    public static <T extends List> void rangeStream(T list, Integer step, BiConsumer<RangeIndex, T> handlerRangeStream) {
        //校验集合
        checkCollection(list);
        //执行rangeStream(遍历整个list)
        rangeStream(list, 0, list.size(), step, handlerRangeStream);
    }

    /**
     * 验证起止索引、step
     *
     * @param start
     * @param stopExclude
     * @param step
     * @param <T>
     */
    private static <T extends Collection> void checkStartAndEndIndex(Integer start, Integer stopExclude, Integer step) {
        if (null == start || null == stopExclude || null == step) {
            throw new MsgRuntimeException("自定义rangeStream起止索引、步长不能为空!");
        }
        if (0 > start || 0 > stopExclude || 0 >= step) {
            throw new MsgRuntimeException("自定义rangeStream起止索引、步长(不可等于0)均需要>=0!");
        }
        if (start >= stopExclude || step > (stopExclude - start)) {
            throw new MsgRuntimeException("自定义rangeStream起止索引、步长不符合规范(start < stopExclude 且 step <= (stopExclude - start))");
        }
    }

    /**
     * 验证集合非空
     *
     * @param collection
     * @param <T>
     */
    private static <T extends Collection> void checkCollection(T collection) {
        if (null == collection || 0 >= collection.size()) {
            throw new MsgRuntimeException("自定义rangeStream 待处理集合不能为空!");
        }
    }

    /**
     * 验证对象非空
     *
     * @param obj
     * @param objDesc
     * @param <T>
     */
    private static <T> void checkEmpty(T obj, String objDesc) {
        if (null == obj) {
            throw new MsgRuntimeException("自定义rangeStream 待处理".concat(objDesc).concat("不能为空!"));
        }
    }

    /**
     * range索引
     */
    public static class RangeIndex {
        /**
         * 当前range的批次索引(第几个range,从0开始)
         */
        private Integer stepIndex;
        /**
         * 当前range的起始索引
         */
        private Integer startIndex;
        /**
         * 当前range的结束索引(不包括当前索引)
         */
        private Integer stopIndexExclude;


        public RangeIndex(Integer stepIndex, Integer startIndex, Integer stopIndexExclude) {
            this.stepIndex = stepIndex;
            this.startIndex = startIndex;
            this.stopIndexExclude = stopIndexExclude;
        }

        public Integer getStepIndex() {
            return stepIndex;
        }

        public Integer getStartIndex() {
            return startIndex;
        }

        public Integer getStopIndexExclude() {
            return stopIndexExclude;
        }

        @Override
        public String toString() {
            return stepIndex + "[" + startIndex + ", " + stopIndexExclude + ")";
        }
    }


   }

测试用例

 public static void main(String[] args) {
        int start = 0, endExclude = 10;

        //设置step=2, 3, 4
        IntStream.range(2, 5).forEach(step -> {
            System.out.println(String.format("<==== 测试rangeStream start=%s, endExclude=%s, step=%s ====>", start, endExclude, step));
            /** 测试rangeStream */
            String indexStr = RangeUtils.rangeStream(start, endExclude, step)
                    .map(String::valueOf)
                    .collect(Collectors.joining(","));
            System.out.println(String.format("start=%s, endExclude=%s, step=%s, indexArray=%s\n", start, endExclude, step, indexStr));
        });
        //设置step=2, 3, 4
        IntStream.range(2, 5).forEach(step -> {
            System.out.println(String.format("<==== 测试rangeStreamWithIndex start=%s, endExclude=%s, step=%s ====>", start, endExclude, step));
            /** 测试rangeStreamWithIndex */
            String indexStr = RangeUtils.rangeStreamWithIndex(start, endExclude, step)
                    .map(RangeIndex::toString)
                    .collect(Collectors.joining(","));
            System.out.println(String.format("start=%s, endExclude=%s, step=%s, indexArray=%s\n", start, endExclude, step, indexStr));
        });


        //定义待拆分集合
        List<Integer> numList = IntStream.range(0, 10).mapToObj(Integer::valueOf).collect(Collectors.toList());
        //设置step=2, 3, 4
        IntStream.range(2, 5).forEach(step -> {
            System.out.println(String.format("<==== 测试rangeStream(仅获取拆分后列表) start=%s, endExclude=%s, step=%s ====>", start, endExclude, step));
            /** 测试rangeStream(仅获取拆分后列表) */
            RangeUtils.rangeStream(numList, start, endExclude, step, (subNumList) -> {
                System.out.println(String.format("%s", subNumList));
            });
            System.out.println();
        });

        //设置step=2, 3, 4
        IntStream.range(2, 5).forEach(step -> {
            System.out.println(String.format("<==== 测试rangeStream(同时获取拆分索引和获取拆分后列表) start=%s, endExclude=%s, step=%s ====>", start, endExclude, step));
            /** 测试rangeStream(同时获取拆分索引和获取拆分后列表) */
            RangeUtils.rangeStream(numList, start, endExclude, step, (rangeIndex, subNumList) -> {
                System.out.println(String.format("%s=%s", rangeIndex, subNumList));
            });
            System.out.println();
        });
}

测试结果

<==== 测试rangeStream start=0, endExclude=10, step=2 ====>
start=0, endExclude=10, step=2, indexArray=0,2,4,6,8

<==== 测试rangeStream start=0, endExclude=10, step=3 ====>
start=0, endExclude=10, step=3, indexArray=0,3,6,9

<==== 测试rangeStream start=0, endExclude=10, step=4 ====>
start=0, endExclude=10, step=4, indexArray=0,4,8

<==== 测试rangeStreamWithIndex start=0, endExclude=10, step=2 ====>
start=0, endExclude=10, step=2, indexArray=0[0, 2),1[2, 4),2[4, 6),3[6, 8),4[8, 10)

<==== 测试rangeStreamWithIndex start=0, endExclude=10, step=3 ====>
start=0, endExclude=10, step=3, indexArray=0[0, 3),1[3, 6),2[6, 9),3[9, 10)

<==== 测试rangeStreamWithIndex start=0, endExclude=10, step=4 ====>
start=0, endExclude=10, step=4, indexArray=0[0, 4),1[4, 8),2[8, 10)

<==== 测试rangeStream(仅获取拆分后列表) start=0, endExclude=10, step=2 ====>
[0, 1]
[2, 3]
[4, 5]
[6, 7]
[8, 9]

<==== 测试rangeStream(仅获取拆分后列表) start=0, endExclude=10, step=3 ====>
[0, 1, 2]
[3, 4, 5]
[6, 7, 8]
[9]

<==== 测试rangeStream(仅获取拆分后列表) start=0, endExclude=10, step=4 ====>
[0, 1, 2, 3]
[4, 5, 6, 7]
[8, 9]

<==== 测试rangeStream(同时获取拆分索引和获取拆分后列表) start=0, endExclude=10, step=2 ====>
0[0, 2)=[0, 1]
1[2, 4)=[2, 3]
2[4, 6)=[4, 5]
3[6, 8)=[6, 7]
4[8, 10)=[8, 9]

<==== 测试rangeStream(同时获取拆分索引和获取拆分后列表) start=0, endExclude=10, step=3 ====>
0[0, 3)=[0, 1, 2]
1[3, 6)=[3, 4, 5]
2[6, 9)=[6, 7, 8]
3[9, 10)=[9]

<==== 测试rangeStream(同时获取拆分索引和获取拆分后列表) start=0, endExclude=10, step=4 ====>
0[0, 4)=[0, 1, 2, 3]
1[4, 8)=[4, 5, 6, 7]
2[8, 10)=[8, 9]

猜你喜欢

转载自blog.csdn.net/luo15242208310/article/details/108355939