Capítulo 03: Estruturas Repetitivas (while, do-while, for clássico e for-each) e Controle de Laços
Especialização em Sistemas com Java 21 LTS • Módulo de Fundamentos
🗺️ Mapa Conceitual do Tópico
flowchart TD
A["Início do Laço"] --> B{"Tipo de Estrutura"}
B -->|Pré-Testado| C["while (condicao)"]
B -->|Determinístico| D["for (init; teste; passo)"]
B -->|Coleções / Arrays| E["for (Tipo item : colecao)"]
B -->|Pós-Testado| F["do { ... } while (condicao);"]
C & D & E --> G{"Condição Verdadeira?"}
G -->|Sim| H["Executa Corpo da Iteração"]
G -->|Não| I["Sai do Laço"]
F --> H
H --> J{"Controle de Fluxo"}
J -->|continue| G
J -->|break| I
J -->|break rotulado| K["Sai de Múltiplos Laços (outer)"]
style A fill:#e1f5fe,stroke:#03a9f4,stroke-width:2px
style B fill:#fff3e0,stroke:#ff9800,stroke-width:2px
style E fill:#ede7f6,stroke:#7e57c2,stroke-width:2px
style K fill:#ffebee,stroke:#f44336,stroke-width:2px
🔁 1. A Tríade Tradicional de Laços no Java
As instruções de repetição permitem executar blocos de código repetidamente com base em critérios booleanos. No nível do bytecode da JVM, todos os laços são traduzidos em sequências de instruções condicionais de salto (goto, ifeq, if_icmplt).
1. while: Repetição Pré-Testada
Utilizado quando a quantidade exata de iterações não é conhecida previamente e depende de um evento externo (ex.: consumo de socket, leitura de arquivo até EOF, polling de filas):
while (filaMensagens.hasPendingMessages()) {
Mensagem msg = filaMensagens.poll();
processar(msg);
}
Se a condição inicial for falsa, o corpo do laço nunca é executado.
2. do-while: Repetição Pós-Testada
Garante que o bloco de instruções seja executado obrigatoriamente pelo menos uma vez, avaliando o predicado apenas ao final de cada ciclo:
int tentativas = 0;
boolean conexaoEstabelecida = false;
do {
tentativas++;
conexaoEstabelecida = conectarSocket();
} while (!conexaoEstabelecida && tentativas < 3);
3. for Clássico: Controle Baseado em Índices
Ideal para iterações numéricas com contador finito e passos regulares:
for (int i = 0; i < tamanho; i += 2) {
System.out.printf("Processando índice par: %d%n", i);
}
📦 2. O Laço Moderno for-each e a Interface Iterable<T>
Introduzido no Java 5 e amplamente utilizado até o Java 21, o for-each (enhanced for loop) oculta a complexidade mecânica de iteradores e índices de vetores.
Desaçucaramento Sintático pelo Compilador:
- Sobre Matrizes (
T[]): O compilador converte internamente em um laço indexadofor (int i = 0; i < arr.length; i++). - Sobre Coleções (
Iterable<T>): O compilador gera código equivalente a:for (Iterator<Transacao> it = lista.iterator(); it.hasNext(); ) { Transacao tx = it.next(); // Corpo do loop }
⚠️ O Perigo do ConcurrentModificationException
Nunca adicione ou remova elementos diretamente da coleção enquanto a percorre em um for-each. Para remoções seguras durante a iteração:
- Utilize
it.remove()diretamente sobre oIterator. - Utilize o método funcional
lista.removeIf(p -> p.isExpirada()).
🕹️ 3. Controle Fino: break, continue e Laços Rotulados (Labels)
Quando operamos com matrizes multidimensionais ou algoritmos de busca aninhados, break e continue padrão afetam apenas o laço imediatamente interno.
Laços Rotulados (Labeled Statements)
O Java permite nomear blocos repetitivos com rótulos seguidos de dois-pontos (label:), viabilizando a interrupção imediata de toda a pilha de iterações sem a necessidade de bandeiras booleanas (boolean flagEncontrado):
buscaMatriz:
for (int linha = 0; linha < matriz.length; linha++) {
for (int col = 0; col < matriz[linha].length; col++) {
if (matriz[linha][col] == ALVO_CRITICO) {
System.out.printf("Alvo localizado em [%d, %d]! Abortando busca.%n", linha, col);
break buscaMatriz; // Encerra o loop externo imediatamente
}
}
}
📊 4. Matriz Comparativa de Estruturas Repetitivas
| Estrutura | Momento da Avaliação | Garantia Mínima de Execução | Manutenção de Estado do Índice | Caso de Uso Ideal |
|---|---|---|---|---|
while |
Antes da 1ª iteração | 0 vezes | Variável declarada externamente | Fluxos de entrada contínuos, leituras assíncronas |
do-while |
Ao final de cada iteração | 1 vez | Variável declarada externamente | Menus de console, handshakes de rede, retries |
for tradicional |
Antes da 1ª iteração | 0 vezes | Escopo restrito ao laço | Varredura com saltos customizados ou ordem reversa |
for-each |
Pela interface Iterator |
0 vezes | Nenhum (apenas o elemento) | Leitura sequencial limpa de coleções e arrays |
⚡ 5. Otimizações da JVM: Unrolling e Custo de Boxing
Em laços críticos de alta taxa de transferência (HFT, processamento gráfico, Big Data):
- Loop Unrolling: O compilador Just-In-Time (C2 JIT) pode desenrolar laços pequenos (ex: 4 em 4 iterações) para eliminar instruções
jumpe otimizar o pipeline da CPU. - Evite Boxing/Unboxing em Laços: Declarar o acumulador como
Double soma = 0.0;força a criação de milhares de instâncias wrappers na Heap a cadasoma += valor;. Use sempre primitivos (double soma = 0.0;).
💻 6. Código de Demonstração Corporativo (Java 21 LTS)
package com.empresa.fundamentos;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
/**
* Processador em lote com tentativas de conexão (do-while) e varredura rotulada (labeled break).
*/
public class ProcessadorLoteOrdens {
public record OrdemServico(long id, String cliente, BigDecimal valor, boolean temFraude) {}
public static boolean tentarHandshakeServidor(int tentativaMax) {
int attempt = 0;
boolean conectado = false;
do {
attempt++;
System.out.printf(" [REDE] Tentativa de conexão ao cluster RPC (%d/%d)...%n", attempt, tentativaMax);
if (attempt == 2) { // Simulação: conecta na 2ª tentativa
conectado = true;
}
} while (!conectado && attempt < tentativaMax);
return conectado;
}
public static void main(String[] args) {
System.out.println("================================================================================");
System.out.println(" PROCESSAMENTO DE LOTES FINANCEIROS COM CONTROLE DE LAÇOS ");
System.out.println("================================================================================");
if (!tentarHandshakeServidor(3)) {
System.err.println("Falha catastrófica: Servidor de liquidação indisponível.");
return;
}
// Simulação de lotes de ordens em matriz bidimensional (Lotes x Ordens)
OrdemServico[][] matrizLotes = {
{ new OrdemServico(101, "Alpha Tech", new BigDecimal("1500.00"), false),
new OrdemServico(102, "Beta Corp", new BigDecimal("3200.00"), false) },
{ new OrdemServico(201, "Gama Log", new BigDecimal("8900.00"), true), // Fraude detectada
new OrdemServico(202, "Delta S/A", new BigDecimal("4100.00"), false) },
{ new OrdemServico(301, "Epsilon Inc", new BigDecimal("12000.00"), false) }
};
BigDecimal volumeLiquidado = BigDecimal.ZERO;
int totalProcessadas = 0;
processamentoLotes:
for (int loteIdx = 0; loteIdx < matrizLotes.length; loteIdx++) {
System.out.printf("🚀 Iniciando processamento do Lote #%d...%n", loteIdx + 1);
for (OrdemServico ordem : matrizLotes[loteIdx]) {
if (ordem.temFraude()) {
System.out.printf("🚨 [SEGURANÇA] Fraude na ordem #%d (%s)! Abortando processamento geral.%n",
ordem.id(), ordem.cliente());
break processamentoLotes; // Interrompe o loop externo
}
volumeLiquidado = volumeLiquidado.add(ordem.valor());
totalProcessadas++;
System.out.printf(" ✅ Ordem #%d aprovada - Cliente: %-12s | Valor: R$ %10.2f%n",
ordem.id(), ordem.cliente(), ordem.valor());
}
}
System.out.println("--------------------------------------------------------------------------------");
System.out.printf("Total de Ordens Liquidadas com Sucesso: %d%n", totalProcessadas);
System.out.printf("Volume Financeiro Total Movimentado : R$ %,10.2f%n", volumeLiquidado);
System.out.println("================================================================================");
}
}