Encodera

Thanks for reading!

Donate to the site — we work hard for you.

How to split a list into chunks

Short answer

Take subList() in steps of the chunk size:

void main() {
    var items = List.of(1, 2, 3, 4, 5, 6, 7);
    int size = 3;
 
    var chunks = new ArrayList<List<Integer>>();
    for (int i = 0; i < items.size(); i += size) {
        chunks.add(items.subList(i, Math.min(i + size, items.size())));
    }
    IO.println(chunks);
}

Output:

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

With a stream

A stream over chunk numbers does the same in one expression:

void main() {
    var items = List.of("a", "b", "c", "d", "e");
    int size = 2;
 
    var chunks = IntStream.range(0, (items.size() + size - 1) / size)
            .mapToObj(i -> items.subList(i * size, Math.min((i + 1) * size, items.size())))
            .toList();
    IO.println(chunks);
}

Output:

[[a, b], [c, d], [e]]

Processing in batches

A typical use is sending data in batches, for example 100 records at a time:

void main() {
    var ids = IntStream.rangeClosed(1, 250).boxed().toList();
    for (int i = 0; i < ids.size(); i += 100) {
        var batch = ids.subList(i, Math.min(i + 100, ids.size()));
        IO.println("batch of " + batch.size() + ", first id " + batch.getFirst());
    }
}

Output:

batch of 100, first id 1
batch of 100, first id 101
batch of 50, first id 201

Common mistake

subList() is a view of the original list, not a copy. If you change the original list afterwards, accessing the part throws:

void main() {
    var items = new ArrayList<>(List.of(1, 2, 3, 4));
    var part = items.subList(0, 2);
    items.add(5);
    IO.println(part);
}

Output:

Exception in thread "main" java.util.ConcurrentModificationException

If you need the parts for a long time, copy them: new ArrayList<>(items.subList(...)).

Functions used in this recipe

Thanks for reading!

Donate to the site — we work hard for you.