A veces tenemos una lista de elementos que queremos procesar pero en vez de hacerlo de uno en uno, queremos hacerlo en bloques. Se puede hacer con el típico bucle anidado que va añadiendo a una lista hasta llegar al tamaño del batch..., pero con Java 8 podemos hacerlo de una forma muy muy sencilla usando streams, y usando generics además podemos dejarla reutilizable.
Con algo tal que así (sí, se puede escribir todo en una linea, pero no es una competición de escribir menos)
public static <T> List<List<T>> splitInBatches(List<T> completeList, int batchSize) { int blocks = (int) Math.ceil(completeList.size() / (float) batchSize); return IntStream.range(0, blocks).mapToObj(count -> { int initList = count * batchSize; int endList = Math.min(completeList.size(), initList + batchSize); return completeList.subList(initList, endList); }).collect(Collectors.toList()); }podemos dividir una lista de elementos y que nos devuelva una lista de listas de elementos, cada una con un tamaño máximo batchSize.
Dado un código
List<String> listaDeCodigos = Arrays.asList("ES","EN","FR"...); for(List<String> batch : splitInBatches(listaDeCodigos,20)) { // Hacer algo con el batch de como máximo 20 códigos }
Podemos procesar la lista de elementos inicial de 20 en 20.
¿Para que nos puede servir? Pues por ejemplo, yo lo he utilizado para procesar una lista de notificaciones pendientes y dividir el trabajo actual de enviar los mails en lotes de X y distribuir los lotes entre los nodos de un cluster. En otro caso lo he utilizado para dividir una consulta SQL muy pesada (de esas que hacen que el servidor de BDD te corte la conexión) en consultas más pequeñas y poder hacerlas de forma concurrente...
No es algo que se use todos los días, pero si alguna vez os pasa, espero que esta solución tan sencilla os sirva.
Happy coding! EJ
No hay comentarios:
Publicar un comentario