foreach, break e continue: Refinando os Laços

foreach, break e continue: Refinando os Laços

O laço foreach, que percorre cada item de um conjunto sem exigir controle manual de índice e elimina os erros de contagem. A aula apresenta também break, que interrompe o laço, e continue, que pula apenas uma repetição — com a orientação de usar ambos com moderação.
Linguagem C#

• • 10 min de leitura

Na aula anterior, dominamos os dois laços fundamentais, o while e o for. Nesta, refinamos esse domínio com três recursos que tornam os laços mais expressivos e mais controláveis. O primeiro é o laço foreach, uma forma especialmente simples e segura de percorrer conjuntos de itens — que apresentaremos aqui em sua forma essencial e que ganhará todo o seu poder na Fase 4, quando aprendermos a guardar muitos valores juntos. Os outros dois são as instruções break e continue, pequenas mas úteis, que dão controle mais fino sobre o andamento de um laço: break interrompe o laço antes da hora, e continue pula para a próxima repetição. Juntos, esses recursos completam seu domínio sobre a repetição.

Uma primeira noção de conjunto de itens

Para entender o foreach, preciso adiantar uma ideia que a Fase 4 desenvolverá plenamente: a de que podemos guardar vários valores juntos numa única estrutura. Até agora, cada variável guardava um só valor. Mas frequentemente queremos guardar uma coleção de valores — vários nomes, várias notas, vários preços. A forma mais básica disso é o array (que estudaremos em detalhe adiante); por ora, veja apenas como se cria um pequeno conjunto de textos, para que o exemplo do foreach faça sentido:

string[] frutas = { "maçã", "banana", "uva" };

Essa linha cria um conjunto chamado frutas contendo três textos. Não se preocupe agora com os detalhes da sintaxe (os colchetes, as chaves); trate-o apenas como "uma caixa com três frutas dentro, nesta ordem". O que nos interessa é: como percorrer cada item desse conjunto, fazendo algo com cada um? É exatamente para isso que serve o foreach.

O laço foreach: para cada item, faça

O foreach (em inglês, "para cada") percorre um conjunto, executando o bloco uma vez para cada item, e entregando o item da vez a uma variável que você nomeia. Sua leitura é quase literal:

string[] frutas = { "maçã", "banana", "uva" };

foreach (string fruta in frutas)   // para cada 'fruta' dentro de 'frutas'...
{
    Console.WriteLine(fruta);       // ...exiba aquela fruta.
}

Leia a linha do foreach em voz alta: "para cada fruta em frutas". A cada repetição, a variável fruta assume o valor de um item do conjunto — na primeira volta, "maçã"; na segunda, "banana"; na terceira, "uva" — e o bloco é executado com aquele valor. Quando todos os itens forem percorridos, o laço termina. O resultado é a exibição das três frutas, uma por linha.

Compare o foreach com o for que faria a mesma coisa. Com for, você precisaria de uma variável de contagem, de saber o tamanho do conjunto, e de acessar cada item pela sua posição — mais peças, mais chances de errar (como contar além do fim do conjunto). O foreach elimina tudo isso: não há contador, não há condição de parada a gerenciar, não há como acessar uma posição inexistente. Você apenas diz "para cada item, faça isto", e o laço cuida do resto. Por isso, sempre que você precisar apenas visitar cada item de um conjunto, sem se importar com posições, o foreach é a escolha mais simples e segura. Sua limitação — e a razão de o for ainda existir — é que o foreach não lhe dá a posição de cada item nem permite modificar a estrutura enquanto a percorre; para esses casos, o for continua sendo necessário. Voltaremos ao foreach com muito mais profundidade na Fase 4; por ora, guarde sua forma essencial e sua leitura natural.

break: interrompendo o laço antes da hora

Às vezes, no meio de um laço, acontece algo que torna desnecessário — ou indesejável — continuar repetindo. A instrução break (em inglês, "quebrar", "romper") interrompe o laço imediatamente, saltando para a instrução seguinte a ele, mesmo que a condição do laço ainda fosse verdadeira ou houvesse mais itens a percorrer. É útil quando você procura algo e o encontra: achado o que buscava, não há razão para continuar.

for (int i = 1; i <= 100; i++)
{
    Console.WriteLine(i);
    if (i == 5)
    {
        Console.WriteLine("Encontrei o 5, parando.");
        break;   // interrompe o laço aqui, mesmo faltando ir até 100
    }
}
Console.WriteLine("Fim.");

Embora o laço fosse programado para ir até 100, o break o interrompe assim que i chega a 5. A execução salta direto para "Fim.". O break é o "botão de parada de emergência" do laço: aciona-o quando a repetição já cumpriu seu propósito antes do previsto. Um uso comum é numa busca dentro de um conjunto — ao encontrar o item procurado, um break evita percorrer o restante à toa.

continue: pulando uma repetição

A instrução continue (em inglês, "continuar") é mais sutil: em vez de encerrar o laço, ela pula o restante do bloco na repetição atual e vai direto para a próxima repetição. É como dizer "para este item, não faça o resto; passe ao próximo". É útil quando você quer processar a maioria dos itens, mas ignorar alguns que atendem a certa condição.

for (int i = 1; i <= 10; i++)
{
    if (i % 2 != 0)   // se i for ímpar...
    {
        continue;     // ...pule o resto e vá para o próximo i
    }
    Console.WriteLine(i);   // esta linha só roda para os pares
}

Neste laço, quando i é ímpar, o continue faz o programa saltar a linha de exibição e ir direto para a próxima repetição — de modo que apenas os números pares são exibidos. A diferença entre break e continue é fundamental e vale fixá-la: break sai do laço por completo; continue apenas pula para a próxima volta. Um encerra a repetição; o outro salta uma iteração e prossegue. (Vale notar que o mesmo efeito — exibir só os pares — poderia ser obtido com um if que envolvesse a exibição; o continue é uma alternativa de estilo, útil sobretudo quando o bloco a pular é longo, deixando a condição de exclusão claramente no início.)

Usar com moderação

Uma palavra de equilíbrio, no espírito do curso. O break e o continue são úteis, mas o uso excessivo deles pode tornar o fluxo de um laço difícil de acompanhar, com múltiplos pontos de saída e salto espalhados pelo bloco. Um laço com muitos break e continue pode confundir quem lê (inclusive você mesmo, depois). Use-os quando genuinamente clarificam a intenção — um break numa busca, um continue para descartar casos indesejados logo no início — e prefira a lógica simples quando ela bastar. Como em quase tudo na programação, a clareza é o valor supremo, e esses recursos servem a ela quando bem empregados, mas a prejudicam quando abusados.

Percorrer um conjunto de itens ficou mais simples e mais seguro. O foreach dispensa o controle manual de índice e, com isso, elimina de saída a classe de erros que nasce de contar errado. Quando o que se quer é visitar cada item, ele é a escolha mais direta e mais legível.

Dois comandos de controle fino completaram o quadro: break interrompe o laço inteiro assim que o objetivo é alcançado, e continue abandona apenas a volta atual e segue para a próxima. São recursos úteis e fáceis de abusar — usados com parcimônia, deixam a intenção explícita; espalhados sem critério, tornam difícil acompanhar o fluxo.

Fontes e leituras recomendadas

Exercícios

Exercício 1

Crie um pequeno conjunto de nomes (string[] nomes = { "Ana", "Beto", "Carla" };) e use um foreach para exibir cada nome com uma saudação, como "Olá, Ana!". Explique, com suas palavras, o que a variável do foreach (por exemplo, nome) representa a cada repetição.

Ver resposta

✓ Resposta: Exemplo:

string[] nomes = { "Ana", "Beto", "Carla" };
foreach (string nome in nomes)
    Console.WriteLine($"Olá, {nome}!");

A variável nome representa, a cada repetição, um item do conjunto: na primeira volta vale "Ana", na segunda "Beto", na terceira "Carla". O foreach a preenche automaticamente com o próximo item a cada iteração, até percorrer todos.

Exercício 2

Escreva um laço for que conte de 1 a 50, mas que use um break para parar assim que encontrar o primeiro múltiplo de 7 (dica: um número é múltiplo de 7 quando i % 7 == 0). Exiba o número encontrado antes de parar.

Ver resposta

✓ Resposta: Exemplo:

for (int i = 1; i <= 50; i++)
{
    if (i % 7 == 0)
    {
        Console.WriteLine($"Primeiro múltiplo de 7: {i}");
        break;
    }
}

O laço iria até 50, mas o break o interrompe assim que encontra o primeiro múltiplo de 7 (o número 7), exibindo-o e saindo do laço sem percorrer o restante.

Exercício 3

Escreva um laço for de 1 a 20 que use continue para exibir apenas os números que não são múltiplos de 3. Depois, reescreva o mesmo comportamento usando um if em vez de continue, e compare as duas abordagens.

Ver resposta

✓ Resposta: Com continue:

for (int i = 1; i <= 20; i++)
{
    if (i % 3 == 0) continue;   // pula os múltiplos de 3
    Console.WriteLine(i);
}

Com if:

for (int i = 1; i <= 20; i++)
{
    if (i % 3 != 0)             // só exibe se NÃO for múltiplo de 3
        Console.WriteLine(i);
}

As duas produzem o mesmo resultado. A versão com continue afasta o caso a ignorar logo no início e deixa o resto do bloco "limpo"; a versão com if envolve a ação numa condição positiva. Para blocos curtos, o if costuma ser mais direto; o continue ganha valor quando o bloco a pular é longo.

Exercício 4

Explique, com suas palavras e um exemplo de cada, a diferença entre break e continue. O que exatamente cada um faz ao ser encontrado dentro de um laço?

Ver resposta

✓ Resposta: break sai do laço por completo: ao ser encontrado, interrompe imediatamente toda a repetição e passa para a instrução seguinte ao laço. Exemplo: num laço de busca, um break ao encontrar o item procurado encerra a busca. continue pula apenas a repetição atual: ao ser encontrado, ignora o restante do bloco naquela volta e vai direto para a próxima iteração, sem encerrar o laço. Exemplo: num laço que processa números, um continue ao encontrar um número inválido salta o processamento daquele número e segue para o próximo. Em resumo: break termina o laço; continue só pula uma volta.

Exercício 5

Sem código: descreva uma situação prática em que o foreach seria mais apropriado que o for para percorrer um conjunto, e uma em que o for seria necessário apesar de o foreach existir. Qual é a limitação do foreach que motiva o segundo caso?

Ver resposta

✓ Resposta: O foreach é mais apropriado, por exemplo, para exibir todos os nomes de uma lista de convidados: você só quer visitar cada item e fazer algo com ele, sem se importar com posições. O for seria necessário, por exemplo, se você quisesse numerar os itens ("1. Ana, 2. Beto...") — o que exige saber a posição de cada um — ou modificar os elementos por posição durante o percurso. A limitação do foreach que motiva o segundo caso é que ele não fornece o índice (a posição) de cada item nem permite alterar a estrutura enquanto a percorre; quando a posição importa, o for, com sua variável de contagem, é indispensável.

Comentários

Mais em Linguagem C#

A List: Uma Coleção que Cresce e Encolhe
A List: Uma Coleção que Cresce e Encolhe

A coleção que resolve a rigidez do array: a List, que cresce e encolhe…

Booleanos e Comparações: Como o Programa Formula Perguntas
Booleanos e Comparações: Como o Programa Formula Perguntas

Como o programa formula perguntas: o tipo bool revisitado, os operadores de…

Conversando com o Usuário: Entrada e Saída
Conversando com o Usuário: Entrada e Saída

Como fazer o programa conversar com quem o usa: exibir informação com…