Is there an elegant way to process a stream in chunks?

前端 未结 7 2043
青春惊慌失措
青春惊慌失措 2020-12-08 00:26

My exact scenario is inserting data to database in batches, so I want to accumulate DOM objects then every 1000, flush them.

I implemented it by putting code in the

7条回答
  •  长情又很酷
    2020-12-08 00:59

    Look's like no, cause creating chunks means reducing stream, and reduce means termination. If you need to maintain stream nature and process chunks without collecting all data before here is my code (does not work for parallel streams):

    private static  BinaryOperator> processChunks(Consumer> consumer, int chunkSize) {
        return (data, element) -> {
            if (data.size() < chunkSize) {
                data.addAll(element);
                return data;
            } else {
                consumer.accept(data);
                return element; // in fact it's new data list
            }
        };
    }
    
    private static  Function> createList(int chunkSize) {
        AtomicInteger limiter = new AtomicInteger(0);
        return element -> {
            limiter.incrementAndGet();
            if (limiter.get() == 1) {
                ArrayList list = new ArrayList<>(chunkSize);
                list.add(element);
                return list;
            } else if (limiter.get() == chunkSize) {
                limiter.set(0);
            }
            return Collections.singletonList(element);
        };
    }
    

    and how to use

    Consumer> chunkProcessor = (list) -> list.forEach(System.out::println);
    
        int chunkSize = 3;
    
        Stream.generate(StrTokenizer::getInt).limit(13)
                .map(createList(chunkSize))
                .reduce(processChunks(chunkProcessor, chunkSize))
                .ifPresent(chunkProcessor);
    
    static Integer i = 0;
    
    static Integer getInt()
    {
        System.out.println("next");
        return i++;
    }
    

    it will print

    next next next next 0 1 2 next next next 3 4 5 next next next 6 7 8 next next next 9 10 11 12

    the idea behind is to create lists in a map operation with 'pattern'

    [1,,],[2],[3],[4,,]...

    and merge (+process) that with reduce.

    [1,2,3],[4,5,6],...

    and don't forget to process the last 'trimmed' chunk with

    .ifPresent(chunkProcessor);
    

提交回复
热议问题