En el desarrollo de aplicaciones Java, la transferencia de datos entre capas suele requerir la duplicación de colecciones o la conversión de listas de un tipo de objeto A a un tipo B. Dependiendo del enfoque utilizado, el impacto en el rendimiento puede ser significativo. A continuación, se presenta una comparativa técnica basada en la ejecución de 1000 iteraciones sobre una lista que contiene 1000 objetos complejos (con aproximadamente 35 campos de diversos tipos).
1. Constructor de ArrayList
Este método utiliza internamente Arrays.copyOf(), el cual delega la operación a System.arraycopy. Al ser un método nativo, interactúa directamente con la memoria, lo que garantiza una eficiencia máxima. Es importante destacar que realiza una copia superficial (shallow copy).
List<ElementoDato> listaOriginal = obtenerDatos(total);
List<ElementoDato> copiaConstructor = new ArrayList<>(listaOriginal);
Rendimiento: ~1 ms (para 1000 ejecuciones).
2. Iteración manual con bucle for-each
Es el enfoque tradicional. Si simplemente se añaden las referencias existentes a una nueva lista, se trata de una copia superficial. Para una copia profunda, sería necesario instanciar un nuevo objeto en cada iteración y copiar sus atributos.
List<ElementoDato> fuente = obtenerDatos(total);
List<ElementoDato> destino = new ArrayList<>(fuente.size());
for (ElementoDato item : fuente) {
destino.add(item);
}
Rendimiento: ~14 ms (para 1000 ejecuciones).
3. Stream API (Collectors.toList)
Introducido en Java 8, ofrece una sintaxis funcional y legible. Al igual que los métodos anteriores, por defecto realiza una copia superficial de los elementos de la colección.
List<ElementoDato> origen = obtenerDatos(total);
List<ElementoDato> resultadoStream = origen.stream().collect(Collectors.toList());
Rendimiento: ~54 ms (para 1000 ejecuciones).
4. Stream combinado con Spring BeanUtils
Este patrón se utiliza cuando se requiere transformar la lista a un nuevo tipo de objeto o asegurar que el primer nivel de los objetos sea una nueva instancia (copia profunda de primer nivel). Las propiedades anidadas siguen siendo referencias compartidas.
List<ElementoDato> datos = obtenerDatos(total);
List<ElementoDato> copiaProfunda = datos.stream().map(entidad -> {
ElementoDato nuevo = new ElementoDato();
BeanUtils.copyProperties(entidad, nuevo);
return nuevo;
}).collect(Collectors.toList());
Rendimiento: ~2468 ms (para 1000 ejecuciones).
5. Utilidad BeanUtil de Hutool
Hutool provee métodos de conveniencia para manejar colecciones de forma genérica. Sin embargo, su rendimiento ha variado drásticamente entre versiones debido a la gestión de bloqueos internos y optimización de caché de propiedades.
List<ElementoDato> listaFuente = obtenerDatos(total);
List<ElementoDato> listaDestino = BeanUtil.copyToList(listaFuente, ElementoDato.class);
- Versión 5.7.13: ~64,674 ms (debido a contención de bloqueos).
- Versión 5.8.24: ~15,874 ms (optimización de caché y eliminación de bloqueos innecesarios).
6. Serialización y Deserialización JSON
Esta es una técnica común para lograr una copia profunda total (deep copy), asegurando que incluso los objetos anidados sean instancias completamente nuevas. No obstante, el proceso de conversión a texto y reconstrucción de objetos es costoso en términos de CPU.
String jsonData = JSON.toJSONString(listaFuente);
List<ElementoDato> copiaTotal = JSON.parseArray(jsonData, ElementoDato.class);
Rendimiento: ~3387 ms (para 1000 ejecuciones).
Resumen de recomendaciones
Si el objetivo es simplemente duplicar la estructura de la lista sin necesidad de clonar los objetos internos, el uso del constructor de ArrayList o System.arraycopy es la opción indiscutible por su velocidad.
Para escenarios que requieren copias profundas o transformación de tipos, el bucle for manual suele ser más eficiente que las librerías de reflexión. Si se opta por herramientas externas como BeanUtils o Hutool, es crítico verificar la versión de la librería, ya que implementaciones ineficientes o bloqueos internos (locks) pueden degradar severamente el rendimiento del sistema en entornos de alta concurrencia.