Una venta puede contener muchos detalles
Hasta ahora usamos referencias entre objetos. Pero una Venta puede contener muchos DetalleVenta, y un catálogo puede contener cientos de productos. Necesitamos una estructura que guarde una cantidad variable de referencias sin crear veinte atributos.

Sin colección
detalle1, detalle2, detalle3… El diseño queda limitado a una cantidad conocida.
Con colección
Un atributo reúne tantos detalles como necesite la venta, sin duplicar campos ni métodos.
Venta, Producto y DetalleVenta; la colección resuelve cómo organizar grupos de esos objetos.¿Qué significa List<E>?
List es una interfaz de Java: establece un contrato para secuencias ordenadas de elementos. Permite elementos repetidos y acceso mediante una posición que comienza en cero.
import java.util.List;
import java.util.ArrayList;
public class Venta {
private List<DetalleVenta> detalles;
public Venta() {
detalles = new ArrayList<>();
}
}La expresión List<DetalleVenta> utiliza un genérico. La letra E representa el tipo de elemento; al escribir DetalleVenta, Java comprueba que los elementos añadidos tengan el tipo esperado.
List no es una clase que podamos construir directamente con new List<>(). Debemos crear una implementación concreta, como ArrayList.Trabajar con List en una venta
Antes de elegir una implementación conviene dominar el contrato común. En este ejemplo suponemos que DetalleVenta ya tiene constructor y método calcularSubtotal(), como en las lecciones previas.
private List<DetalleVenta> detalles = new ArrayList<>();
public void agregarDetalle(DetalleVenta detalle) {
detalles.add(detalle);
}
public int cantidadDeRenglones() {
return detalles.size();
}
public double calcularTotal() {
double total = 0;
for (DetalleVenta detalle : detalles) {
total += detalle.calcularSubtotal();
}
return total;
}| Operación | ¿Para qué sirve? | Ejemplo |
|---|---|---|
add(e) | Agrega un elemento | Nuevo detalle de venta |
get(i) | Obtiene el elemento en la posición i | Primer detalle: índice 0 |
size() | Devuelve la cantidad de elementos | Número de renglones |
remove(i) | Elimina por índice | Quitar una fila |
contains(e) | Busca según igualdad (equals) | Consultar si hay un objeto |
clear() | Vacía la lista | Reiniciar una lista temporal |
size()-1; además, contains utiliza equals, por lo que para comparar productos por código debemos definir la igualdad correctamente o realizar una búsqueda por código.ArrayList frente a LinkedList
Las dos clases implementan List, pero organizan internamente sus datos de modo distinto.
ArrayList
Nuestra opción habitualGuarda referencias en un arreglo redimensionable. Es muy eficiente para recorrer y consultar por índice.
LinkedList
Guarda elementos enlazados. Puede insertar o eliminar eficientemente cuando ya tenemos la posición mediante un iterador, pero acceder por índice requiere recorrer enlaces.
| Operación | ArrayList | LinkedList |
|---|---|---|
get(i) | O(1) | O(n) |
| Agregar al final | O(1) amortizado | O(1) |
| Insertar/eliminar en medio por índice | O(n), desplaza elementos | O(n) para llegar al lugar |
| Insertar/eliminar con iterador ya situado | Puede desplazar elementos | O(1) para modificar enlaces |
| Recorrer secuencialmente | Buena localidad de memoria | Más objetos y enlaces |
Para La Viñeta escogeremos normalmente ArrayList: vamos a listar productos, mostrarlos en JTable, recorrerlos y consultar elementos. LinkedList es importante conocerla, pero no es automáticamente más rápida al insertar o eliminar.
ArrayList por defecto cuando no existe un requisito concreto que favorezca otra implementación. Medir antes de optimizar.Polimorfismo: cambia el objeto, no el contrato
La variable puede declararse con el tipo de la interfaz mientras que el objeto pertenece a una clase que la implementa. Esa es una forma de polimorfismo por subtipo.
List<Producto> productos = new ArrayList<>();
// También es válido:
productos = new LinkedList<>();
productos.add(new Producto(101, "Mafalda 1", 450, 8));
System.out.println(productos.size());Las operaciones add y size siguen funcionando porque pertenecen al contrato List. La implementación concreta determina cómo se ejecutan internamente.
public static void mostrarProductos(List<Producto> productos) {
for (Producto producto : productos) {
System.out.println(producto.getNombre());
}
}Este método acepta indistintamente un ArrayList<Producto> o un LinkedList<Producto> sin duplicar el código.
CrudDAO<Producto> y su implementación JDBC.Ordenar con sort y Comparator
Para mostrar un catálogo ordenado por nombre o precio podemos utilizar sort. Hay dos formas útiles: lista.sort(comparador) y Collections.sort(lista, comparador).
import java.util.Comparator;
import java.util.List;
productos.sort(
Comparator.comparingDouble(Producto::getPrecio)
);productos.sort(
Comparator.comparing(
Producto::getNombre,
String.CASE_INSENSITIVE_ORDER
)
);Comparator indica cómo comparar dos productos. sort modifica el orden de los elementos de la lista. No cambia el código ni el precio de cada producto.Si quisiéramos definir el orden «natural» de la clase usaríamos Comparable, pero por ahora es más flexible pasar distintos Comparator según lo que el usuario quiere ver.
Conjuntos, mapas y árboles: ¿qué más existe?
No todo grupo de datos necesita ser una lista. Java ofrece otras interfaces e implementaciones dentro del Java Collections Framework, cada una con un propósito.
Set — conjuntos
Evitan elementos duplicados según la igualdad definida.
HashSet: sin orden garantizado.LinkedHashSet: conserva orden de inserción.TreeSet: mantiene ordenados los elementos.
Ejemplo: códigos de categorías que no deben repetirse.
Map — diccionarios
Relacionan claves con valores; las claves no se repiten.
HashMap: búsqueda por clave.LinkedHashMap: orden de inserción.TreeMap: claves ordenadas.
Ejemplo: código de producto → producto.
Set<String> categorias = new HashSet<>();
categorias.add("Manga");
categorias.add("Manga"); // No agrega un duplicado
Map<Long, Producto> porCodigo = new HashMap<>();
porCodigo.put(101L, producto);
Producto encontrado = porCodigo.get(101L);¿Y los árboles?
Un árbol es una estructura jerárquica de nodos. No es una única «clase colección» para cualquier árbol: Java ofrece, entre otras, TreeSet y TreeMap, que mantienen elementos o claves ordenados mediante estructuras arbóreas equilibradas.
También existen Queue (colas), Deque (doble extremo), ArrayDeque y PriorityQueue. Basta reconocerlas por ahora; las trabajaremos cuando exista un problema que las necesite.
Map es parte del framework de colecciones, pero no extiende la interfaz Collection. Un TreeSet no es lo mismo que una lista ordenada: no conserva duplicados según su criterio de comparación.Una guía de elección
| Necesidad | Abstracción | Implementación típica |
|---|---|---|
| Detalles de una venta, ordenados por posición | List<DetalleVenta> | ArrayList |
| Etiquetas sin repetidos | Set<String> | HashSet |
| Encontrar productos por código | Map<Long, Producto> | HashMap |
| Productos ordenados por nombre | List<Producto> + Comparator | ArrayList + sort |
| Claves siempre ordenadas | NavigableMap | TreeMap |
Una estructura no sustituye el análisis OO: primero entendemos las reglas de la tienda y después escogemos cómo almacenar y consultar sus objetos.
¿Qué colección elegirías?
1. Un método debe aceptar listas de productos sin importar la implementación concreta. ¿Qué tipo declaramos como parámetro?
2. Necesitamos obtener productos muchas veces mediante su posición. ¿Qué implementación de List suele ser la opción más apropiada?
3. Queremos asociar cada código único con su Producto. ¿Qué estructura corresponde?
4. ¿Qué significa el polimorfismo de List?
List<DetalleVenta>, qué implementación seleccionarías, qué ocurre al cambiarla y cuándo necesitarías un Map en la tienda.Continuidad: con estas herramientas podremos gestionar objetos en memoria, crear interfaces gráficas con Swing y, más adelante, implementar persistencia mediante DAO y JDBC.
PROGRAMACIÓN AVANZADA