Как разбить список на части
Короткий ответ
Берите subList() шагами по размеру части:
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);
}Результат:
[[1, 2, 3], [4, 5, 6], [7]]Через поток
Поток по номерам частей делает то же самое одним выражением:
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);
}Результат:
[[a, b], [c, d], [e]]Обработка пачками
Типичное применение — отправлять данные пачками, например по 100 записей:
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());
}
}Результат:
batch of 100, first id 1
batch of 100, first id 101
batch of 50, first id 201Частая ошибка
subList() — это вид на исходный список, а не копия. Если после этого изменить исходный список, обращение к части выбросит исключение:
void main() {
var items = new ArrayList<>(List.of(1, 2, 3, 4));
var part = items.subList(0, 2);
items.add(5);
IO.println(part);
}Результат:
Exception in thread "main" java.util.ConcurrentModificationExceptionЕсли части нужны надолго, копируйте их: new ArrayList<>(items.subList(...)).
Функции из этого ответа
- List.subList() — Возвращает часть списка между двумя индексами.
- IntStream.range() — Создаёт поток целых чисел из диапазона.
- Collectors.groupingBy() — Сборщик, который раскладывает элементы по группам с общим ключом.