1. Introducción
Empecemos con una pregunta: ¿para qué necesitamos meter un bucle dentro de otro? Ocurre que a menudo nuestros datos o tareas no están organizados en una sola línea, sino, por ejemplo, en una tabla, una cuadrícula o incluso en una estructura multidimensional. Supongamos que quieres mostrar en pantalla la tabla de multiplicar, recorrer un array bidimensional o calcular las intersecciones entre todos los pares de elementos. Aquí un solo bucle no basta — necesitas un bucle dentro de otro.
En programación, un bucle anidado es como dos despertadores: el exterior empieza a sonar y dentro de él se pone en marcha otro que sonará cada vez mientras el primero esté activo. Así, mientras dura una iteración «externa», la interna recorre todo su camino (y lo hace una y otra vez para cada iteración de la externa).
Un buen ejemplo son las horas y los minutos. Las horas son el bucle externo de 0 a 23, y los minutos el bucle interno de 0 a 59. Por cada cambio en el bucle externo, el interno recorre todos sus valores.
2. Sintaxis de los bucles anidados
En Java, la sintaxis de los bucles anidados no difiere de la de los bucles normales: simplemente escribes un bucle dentro del cuerpo de otro. Veamos ejemplos con for y while:
// Bucle externo for
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 4; j++) // Bucle interno for
{
System.out.print(i + "," + j + " ");
}
System.out.println(); // Salto de línea después del bucle interno
}
Aquí el bucle externo controla la variable i (de 0 a 2) y el interno la variable j (de 0 a 3). Para cada valor de i, el bucle interno recorre completamente desde j == 0 hasta j == 3. Si ejecutas este código, verás una tabla de coordenadas clara:
0,0 0,1 0,2 0,3
1,0 1,1 1,2 1,3
2,0 2,1 2,2 2,3
Un ejemplo análogo con while:
int i = 0;
while (i < 3)
{
int j = 0;
while (j < 4)
{
System.out.print(i + "," + j + " ");
j++;
}
System.out.println();
i++;
}
Ten en cuenta: en cada pasada del bucle externo, la variable del bucle interno (j) debe reinicializarse; de lo contrario, ¡solo veremos una línea!
3. Ejemplos de trabajo con bucles anidados
Ejemplo 1: impresión de un tablero de ajedrez (8x8)
Que nuestra primera tarea sea mostrar en pantalla un tablero de ajedrez clásico en forma de casillas negras y blancas (supongamos que «#» es negra y «.» blanca). Lo implementamos con bucles anidados for:
for (int row = 0; row < 8; row++)
{
for (int col = 0; col < 8; col++)
{
// Si la suma de los índices de fila y columna es par, la celda es blanca; en caso contrario, es negra
if ((row + col) % 2 == 0)
System.out.print("_");
else
System.out.print("#");
}
System.out.println(); // Salto de línea tras cada fila
}
Resultado:
_#_#_#_#
#_#_#_#_
_#_#_#_#
#_#_#_#_
_#_#_#_#
#_#_#_#_
_#_#_#_#
#_#_#_#_
Punto importante: la anidación garantiza que, para cada fila (row), recorramos por completo todas las columnas (col). Sin anidación no obtendríamos la estructura del tablero — solo una fila o una columna.
Ejemplo 2: tabla de multiplicar
¡Uno de los candidatos clásicos a los bucles anidados! Vamos a mostrar la tabla de multiplicar del 1 al 9:
for (int i = 1; i <= 9; i++)
{
for (int j = 1; j <= 9; j++)
{
System.out.print(i * j + "\t");
}
System.out.println();
}
El formateo i * j + "\t" añade tabulaciones para que la tabla quede alineada.
Resultado:
1 2 3 4 5 6 7 8 9
2 4 6 8 10 12 14 16 18
3 6 9 12 15 18 21 24 27
4 8 12 16 20 24 28 32 36
...
9 18 27 36 45 54 63 72 81
4. Bucles anidados y su control — matices
Sobre el efecto de break y continue en bucles anidados
¡Aquí tropiezan muchos principiantes! Si usas break o continue en el bucle interno, afectan solo a ese bucle. El externo continúa su trabajo como si nada.
Ejemplo: salida anticipada solo del bucle interno
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 5; j++)
{
if (j == 3)
break; // ¡salimos solo del bucle interno!
System.out.print(i + "," + j + " ");
}
System.out.println();
}
Resultado:
0,0 0,1 0,2
1,0 1,1 1,2
2,0 2,1 2,2
Si necesitas salir a la vez de dos bucles anidados (por ejemplo, terminar urgentemente una búsqueda ante la primera coincidencia en una tabla), se suele usar una bandera o alguna técnica específica (por ejemplo, return — si todo ocurre dentro de una función).
5. Visualización de bucles anidados
A veces cuesta «ver» la secuencia de ejecución de los bucles anidados. Observa el siguiente diagrama de flujo:
En forma de tabla — ¿cuántas iteraciones en total habrá con i de 1 a 3 y j de 1 a 4?
| i | j (se recorre para cada i) | Iteraciones del bucle interno |
|---|---|---|
| 1 | 1, 2, 3, 4 | 4 |
| 2 | 1, 2, 3, 4 | 4 |
| 3 | 1, 2, 3, 4 | 4 |
| Total: 3 × 4 = 12 |
6. Errores y trampas al trabajar con bucles anidados
Un error común es inicializar incorrectamente la variable del bucle interno. Por ejemplo, declararla fuera del bucle externo, pero no reiniciarla en cada paso. Como resultado, el bucle interno puede no ejecutarse en absoluto o hacerlo de forma incorrecta.
int j = 0;
for (int i = 0; i < 3; i++)
{
while (j < 4) // ¡Ups! j ya podría ser igual a 4 después de la primera iteración.
{
System.out.print(i + "," + j + " ");
j++;
}
System.out.println();
}
Aquí el bucle se ejecutará solo una vez. ¡No olvides inicializar las variables de los bucles internos dentro de los externos!
Además, si por accidente escribes dos bucles anidados con las mismas variables (for (int i = 0; ...) { for (int i = 0; ...) { ... } }), el compilador se quejará: la variable ya está definida.
GO TO FULL VERSION