Sentencias etiquetadas en Java
Usa etiquetas en Java para hacer break o continue en bucles externos desde dentro de bucles anidados.
Un break simple sale del bucle más interno y un continue simple omite una iteración del mismo. Cuando estás dentro de bucles anidados y necesitas controlar el bucle externo desde el interno, Java te ofrece las sentencias etiquetadas: un nombre que puedes asociar a un bucle, y un break o continue que lo apunta por ese nombre.
Este capítulo cubre cómo definir una etiqueta, cómo el break y continue etiquetados cambian el flujo, cuándo usarlos (raramente) y las alternativas más claras que deberías considerar primero.
Esto es lo más parecido que tiene Java a goto — y está intencionalmente limitado a bucles (y switch).
Definir una etiqueta
Una etiqueta es un identificador seguido de dos puntos, colocado inmediatamente antes de un bucle:
outer:
for (int i = 0; i < 5; i++) {
// ...
}El nombre (outer aquí) sigue las mismas reglas que cualquier identificador Java. No es obligatorio llamarlo outer — searchLoop, rows, cualquier nombre válido funciona. Elige un nombre que indique por qué está la etiqueta.
break etiquetado
break <label>; sale del bucle marcado con esa etiqueta, sin importar cuán profundamente anidado estés dentro de él:
int[][] grid = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
int target = 5;
int foundRow = -1, foundCol = -1;
search:
for (int r = 0; r < grid.length; r++) {
for (int c = 0; c < grid[r].length; c++) {
if (grid[r][c] == target) {
foundRow = r;
foundCol = c;
break search;
}
}
}
System.out.println("found at " + foundRow + "," + foundCol);Sin el break etiquetado, necesitarías una variable bandera o reestructurar el código. Con él, sales de ambos bucles a la vez en el momento en que se encuentra el objetivo.
continue etiquetado
continue <label>; omite el resto de ambas la iteración interna actual y continúa con la siguiente iteración del bucle externo etiquetado:
rowLoop:
for (int r = 0; r < grid.length; r++) {
for (int c = 0; c < grid[r].length; c++) {
if (grid[r][c] < 0) {
continue rowLoop; // skip the rest of this row
}
process(grid[r][c]);
}
}Cuando el bucle interno encuentra un valor negativo, se omite el resto de esa fila y se continúa con la siguiente.
Úsalos con moderación
Las etiquetas funcionan, pero es fácil abusar de ellas. Siempre que vayas a usar una, considera primero las alternativas:
-
Extrae un método auxiliar. Dentro de un método, un
returnsimple sale de todos los bucles a la vez y suele ser más claro:static int[] find(int[][] grid, int target) { for (int r = 0; r < grid.length; r++) { for (int c = 0; c < grid[r].length; c++) { if (grid[r][c] == target) return new int[]{r, c}; } } return null; } -
Usa una bandera — un poco menos limpio pero explícito y sin
goto:boolean found = false; for (int r = 0; !found && r < grid.length; r++) { for (int c = 0; c < grid[r].length; c++) { if (grid[r][c] == target) { found = true; break; } } } -
Usa streams para problemas de filtrado en lugar de bucles anidados.
Recurre a las etiquetas cuando las alternativas realmente perjudican la legibilidad — típicamente con dos o tres niveles de profundidad y con una intención clara de "abortar la búsqueda" o "siguiente iteración externa".
Etiquetas y switch
Las etiquetas también funcionan con switch, aunque es poco frecuente:
sw:
switch (cmd) {
case "x":
if (someCondition) break sw;
// ...
break;
}En la práctica, esto nunca aporta más claridad que un break simple.
Un ejemplo práctico
Qué sigue
Has terminado los capítulos de flujo de control: condicionales, el operador ternario, switch, bucles y las sentencias que los interrumpen. A continuación viene la parte sobre métodos — cómo empaquetar bloques de código para poder invocarlos por nombre.