Instruções Rotuladas em Java
Use rótulos em Java para interromper ou continuar laços externos a partir de laços aninhados.
Um break simples sai do laço mais interno e um continue simples pula uma iteração dele. Quando você está dentro de laços aninhados e precisa controlar o laço externo a partir do interno, Java oferece as instruções rotuladas: um nome que você pode associar a um laço, e um break ou continue que o referencia por esse nome.
Este capítulo aborda como definir um rótulo, como o break e o continue rotulados alteram o fluxo, quando (raramente) usá-los e as alternativas mais limpas a considerar primeiro.
Esta é a coisa mais próxima que Java tem de goto — e é intencionalmente limitada a laços (e switch).
Definindo um rótulo
Um rótulo é um identificador seguido de dois-pontos, colocado imediatamente antes de um laço:
outer:
for (int i = 0; i < 5; i++) {
// ...
}O nome (outer aqui) segue as mesmas regras de qualquer identificador Java. Não há obrigação de chamá-lo de outer — searchLoop, rows ou qualquer nome válido funciona. Escolha um nome que diga por que o rótulo está ali.
break rotulado
break <label>; sai do laço marcado com aquele rótulo, independentemente de quão profundamente aninhado você esteja dentro dele:
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);Sem o break rotulado, você precisaria de uma variável de controle ou teria que reestruturar o código. Com ele, você sai de ambos os laços ao mesmo tempo no instante em que o alvo é encontrado.
continue rotulado
continue <label>; pula o restante da iteração interna atual e continua com a próxima iteração do laço externo rotulado:
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]);
}
}Quando o laço interno encontra um valor negativo, o restante daquela linha é ignorado e passamos para a próxima linha.
Use com moderação
Os rótulos funcionam, mas são fáceis de abusar. Sempre que você sentir vontade de usar um, considere as alternativas primeiro:
-
Extraia um método auxiliar. Dentro de um método, um
returnsimples sai de todos os laços de uma vez e costuma ser mais 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; } -
Use uma variável de controle — um pouco menos elegante, mas explícita e sem
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; } } } -
Use streams para problemas de filtragem em vez de laços aninhados.
Recorra a rótulos quando as alternativas realmente prejudicam a legibilidade — tipicamente em dois ou três níveis de profundidade com uma intenção clara de "abortar a busca" ou "próxima iteração externa".
Rótulos e switch
Rótulos também funcionam com switch, embora seja raro:
sw:
switch (cmd) {
case "x":
if (someCondition) break sw;
// ...
break;
}Na prática, isso nunca adiciona clareza em relação a um break simples.
Um exemplo completo
O que vem a seguir
Você concluiu os capítulos de fluxo de controle: condicionais, o operador ternário, switches, laços e as instruções que os interrompem. O próximo tópico é a parte sobre métodos — agrupando blocos de código para que você possa chamá-los pelo nome.