Além de seus usos com a instrução switch e os laços, a instrução break pode ser em- pregada individualmente para fornecer uma forma “civilizada” da instrução goto. Java não tem uma instrução goto, porque ela fornece uma maneira desestruturada de alterar o fluxo de execução do programa. Geralmente programas que fazem amplo uso de goto são de compreensão e manutenção difíceis. No entanto, há alguns locais em que goto é um artifício útil e legítimo. Por exemplo, goto pode ser útil na saída de um conjunto de laços profundamente aninhado. Para tratar essas situações, Java define uma forma ex- pandida da instrução break. Usando essa forma de break, você pode, por exemplo, sair de um ou mais blocos de código. Esses blocos não precisam fazer parte de um laço ou de um switch. Podem ser qualquer bloco. Além disso, você pode especificar exatamen- te onde a execução continuará, porque essa forma de break funciona com um rótulo. A instrução break fornece os benefícios de um goto sem alguns de seus problemas.
A forma geral da instrução break rotulada é mostrada aqui: break rótulo;
Nesse caso, rótulo é o nome que identifica uma instrução ou um bloco de código. Quan- do essa forma de break é executada, o controle é transferido para fora da instrução ou do bloco rotulado. A instrução ou bloco rotulado deve incluir a instrução break, mas não precisa ser o bloco imediatamente externo. Ou seja, você pode usar uma instrução break rotulada para sair de um conjunto de blocos aninhados, por exemplo, mas não pode usá-la para transferir o controle para um bloco de código que não a inclua.
Para nomear uma instrução ou bloco, insira um rótulo no início dele. Um rótulo é qualquer identificador Java válido seguido por dois pontos. Uma vez que você tiver rotulado uma instrução ou bloco, poderá usar esse rótulo como alvo de uma instrução break. Isso fará a execução ser retomada no fim da instrução ou bloco. Por exemplo, o programa a seguir mostra três blocos aninhados:
// Usando break com um rótulo. class Break4 {
int i;
for(i=1; i<4; i++) { one: {
two: { three: {
System.out.println("\ni is " + i);
if(i= =1) break one;
if(i= =2) break two;
if(i= =3) break three;
// essa parte nunca será alcançada System.out.println("won't print"); }
System.out.println("After block three."); }
System.out.println("After block two."); }
System.out.println("After block one."); }
System.out.println("After for."); }
}
A saída do programa é mostrada aqui:
i is 1
After block one.
i is 2
After block two. After block one.
i is 3
After block three. After block two. After block one. After for.
Examinemos o programa com mais cuidado para entender exatamente por que essa saída é produzida. Quando i é igual a 1, a primeira instrução if é bem-sucedida, cau- sando uma parada no fim do bloco de código definido pelo rótulo one. Isso faz After block one. ser exibido. Quando i é igual a 2, o segundo if é bem-sucedido, fazendo o controle ser transferido para o fim do bloco rotulado com two. Isso faz as mensagens After block two. e After block one. serem exibidas, nessa ordem. Quando i é igual a 3, o terceiro if é bem-sucedido e o controle é transferido para o fim do bloco rotulado com three. Agora, as três mensagens são exibidas.
Vejamos outro exemplo. Dessa vez, break está sendo usado para saltar para fora de uma série de laços for aninhados. Quando a instrução break do laço interno é executada, o controle do programa salta para o fim do bloco definido pelo laço for externo, que foi rotulado com done. Isso faz os outros três laços serem ignorados.
// Outro exemplo do uso de break com um rótulo. class Break5 {
public static void main(String[] args) {
done:
for(int i=0; i<10; i++) { for(int j=0; j<10; j++) { for(int k=0; k<10; k++) { System.out.println(k + " ");
if(k == 5) break done; // salta para done }
System.out.println("After k loop"); // não será executado }
System.out.println("After j loop"); // não será executado }
System.out.println("After i loop"); }
}
A saída do programa é mostrada abaixo:
0 1 2 3 4 5 After i loop
É muito importante o local exato onde um rótulo é inserido – principalmente no tra- balho com laços. Por exemplo, considere o programa a seguir:
// É importante onde o rótulo é inserido. class Break6 {
public static void main(String[] args) { int x=0, y=0;
// aqui, insere o rótulo antes da instrução for. stop1: for(x=0; x < 5; x++) {
for(y = 0; y < 5; y++) {
if(y = = 2) break stop1;
System.out.println("x and y: " + x + " " + y); }
}
System.out.println();
// agora, insere o rótulo imediatamente antes de {
for(x=0; x < 5; x++)
stop2: {
if(y = = 2) break stop2;
System.out.println("x and y: " + x + " " + y); }
} } }
A saída do programa é esta:
x and y: 0 0 x and y: 0 1 x and y: 0 0 x and y: 0 1 x and y: 1 0 x and y: 1 1 x and y: 2 0 x and y: 2 1 x and y: 3 0 x and y: 3 1 x and y: 4 0 x and y: 4 1
No programa, os dois conjuntos de laços aninhados são iguais exceto por uma coisa. No primeiro conjunto, o rótulo precede a instrução for externa. Nesse caso, quando break é executado, transfere o controle para o fim do bloco for inteiro, saltando as outras iterações do laço externo. No segundo conjunto, o rótulo precede a chave de abertura do for externo. Logo, quando break stop2 é executado, o controle é transferido para o fim do bloco for externo e não para o fim do laço. Isso faz a próxima iteração ocorrer.
Lembre-se de que você não pode usar a instrução break com um rótulo que não foi definido para uma instrução ou bloco que a inclua. Por exemplo, o programa abaixo é inválido e não será compilado:
// Este programa contém um erro. class BreakErr {
public static void main(String[] args) {
one: for(int i=0; i<3; i++) {
System.out.print("Pass " + i + ": "); }
for(int j=0; j<100; j++) {
if(j = = 10) break one; // ERRADO
System.out.print(j + " "); }
} }
Como o laço for rotulado com one não inclui a instrução break do segundo laço for, não é possível transferir o controle para esse rótulo.
Pergunte ao especialista
P
Você diz que goto é desestruturado e que break com um rótulo oferece uma alter-nativa melhor. Mas, convenhamos, usar break com um rótulo, que pode resultar em muitas linhas de código e níveis de aninhamento sendo removidos por break, também não desestrutura o código?
R
Uma resposta rápida seria sim! No entanto, nos casos em que uma mudança drásticaé necessária no fluxo do programa, usar break com um rótulo ainda mantém alguma estrutura porque você só pode saltar para fora de uma instrução ou bloco externo rotulado. Não pode saltar para qualquer instrução ou bloco arbitrário. Em contrapartida, goto basica- mente não tem estrutura!