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 201Common 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.ConcurrentModificationExceptionIf you need the parts for a long time, copy them: new ArrayList<>(items.subList(...)).
Functions used in this recipe
- List.subList() — Returns the part of a list between two indexes.
- IntStream.range() — Creates a stream of integers from a range.
- Collectors.groupingBy() — A collector that sorts elements into groups that share a key.