O que é controle de fluxo (decisão)
Controle de fluxo é o conjunto de estruturas que permite ao programa escolher caminhos diferentes de execução com base em condições. Em Java, as decisões mais comuns são feitas com if/else, switch e, em casos pontuais, com a expressão condicional (operador ternário ?:). O objetivo é transformar regras de negócio (ex.: “se renda for maior que X, então alíquota é Y”) em código claro, testável e fácil de manter.
Decisões com if/else
Quando usar
- Quando a condição é booleana e pode envolver intervalos, comparações e combinações (ex.: faixa de valores, múltiplos critérios).
- Quando você precisa de lógica mais flexível do que uma simples comparação de igualdade.
Estrutura básica
if (condicao) { // caminho A} else { // caminho B}Você pode encadear múltiplas alternativas com else if:
if (condicao1) { // A} else if (condicao2) { // B} else { // C (padrão)}Boas práticas para evitar aninhamento excessivo
- Preferir “guard clauses” (retornos antecipados) em métodos: reduzem níveis de indentação e deixam as regras mais lineares.
- Extrair condições para variáveis booleanas com nomes claros: melhora legibilidade e facilita testes manuais.
- Ordenar faixas do mais específico para o mais geral (ou do menor para o maior, dependendo da regra), garantindo que cada caso seja alcançável.
Exemplo prático: validação com guard clauses
Imagine uma regra: só aprovar um cadastro se idade for válida e o e-mail não estiver vazio.
static boolean aprovarCadastro(int idade, String email) { if (idade < 0 || idade > 130) { return false; } if (email == null || email.isBlank()) { return false; } return true;}Note como o método evita if aninhados. Cada regra “barra” o fluxo cedo, e o final fica simples.
Passo a passo: regra de faixa de imposto (simples)
Vamos criar uma regra didática de imposto por faixas (valores fictícios):
- Ouça o áudio com a tela desligada
- Ganhe Certificado após a conclusão
- + de 5000 cursos para você explorar!
Baixar o aplicativo
- Até 2000.00: isento
- De 2000.01 até 5000.00: 10%
- Acima de 5000.00: 20%
Passo 1: Defina as entradas e saídas (renda → imposto).
Passo 2: Ordene as condições por faixa.
Passo 3: Calcule e retorne o imposto.
static double calcularImposto(double renda) { if (renda <= 2000.00) { return 0.0; } else if (renda <= 5000.00) { return renda * 0.10; } else { return renda * 0.20; }}Passo 4: Faça testes manuais com valores de fronteira (ver seção “Testes manuais”).
Decisões com switch
Quando usar
- Quando você escolhe um caminho com base em um valor discreto (ex.: opção de menu, categoria, código).
- Quando a comparação é por igualdade (um valor entre alternativas).
O switch tradicional funciona bem para menus e mapeamentos simples. Versões modernas do Java também oferecem formas mais expressivas, como switch com seta (->) e switch como expressão (retornando valor), quando disponíveis no seu JDK.
Switch tradicional (com break)
Sem break, ocorre “fall-through” (o fluxo continua no próximo case). Em geral, isso é fonte de bugs em menus, então use break quando cada caso deve ser exclusivo.
static String nomeDoDia(int dia) { switch (dia) { case 1: return "Segunda"; case 2: return "Terça"; case 3: return "Quarta"; default: return "Inválido"; }}Como cada case retorna, não é necessário break neste exemplo.
Switch moderno com seta (mais legível)
Em JDKs mais recentes, você pode usar a forma com seta, que evita break e reduz erros de fall-through:
static String categoriaPorCodigo(int codigo) { return switch (codigo) { case 1 -> "Básico"; case 2 -> "Intermediário"; case 3 -> "Avançado"; default -> "Desconhecido"; };}Perceba que aqui o switch é uma expressão: ele produz um valor que você retorna diretamente.
Switch moderno com bloco e yield
Quando um caso precisa de mais de uma instrução (ex.: validar, calcular, montar texto), você pode usar bloco e yield para devolver o valor daquele caso:
static String mensagemDeMenu(int opcao) { return switch (opcao) { case 1 -> "Listar itens"; case 2 -> { String msg = "Cadastrar item"; yield msg; } case 3 -> "Sair"; default -> "Opção inválida"; };}Exemplo prático: menu de console (estrutura de decisão)
Este exemplo foca na decisão (não em loops). Você lê uma opção e decide a ação:
import java.util.Scanner;public class MenuSimples { public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.println("1 - Consultar saldo"); System.out.println("2 - Depositar"); System.out.println("3 - Sair"); System.out.print("Escolha: "); int opcao = sc.nextInt(); String acao = switch (opcao) { case 1 -> "Consultando saldo..."; case 2 -> "Iniciando depósito..."; case 3 -> "Encerrando..."; default -> "Opção inválida."; }; System.out.println(acao); sc.close(); }}Dica: se seu JDK não suportar a forma moderna, use o switch tradicional com case e break.
Operador ternário (expressão condicional ?:)
Quando usar (uso criterioso)
- Para escolhas simples entre dois valores.
- Quando melhora a legibilidade e evita um
if/elsemuito curto.
Evite ternários aninhados e expressões longas: isso costuma piorar a leitura e dificultar depuração.
Exemplo simples
static String classificarIdade(int idade) { return (idade >= 18) ? "Maior de idade" : "Menor de idade";}Comparação: if/else vs ternário
Se você precisa executar múltiplas ações (imprimir, calcular, validar, registrar), prefira if/else. Se é apenas escolher um valor, o ternário pode ser adequado.
// Bom uso: escolher um valordouble desconto = (clienteVip) ? 0.15 : 0.05;// Evite: ternário com lógica extensa e difícil de lerdouble taxa = (renda <= 2000) ? 0 : (renda <= 5000) ? 0.10 : 0.20;No segundo caso, um if/else if/else tende a ficar mais claro.
Organizando regras com clareza
1) Nomeie as condições
boolean isIsento = renda <= 2000.00;boolean isFaixaIntermediaria = renda <= 5000.00;Isso ajuda a “ler” a regra como texto.
2) Prefira tabelas mentais (faixas) e valide fronteiras
Para regras por faixa, escreva primeiro as fronteiras e decida se os limites são inclusivos (<=) ou exclusivos (<). Inconsistências aqui geram bugs difíceis (ex.: 2000.00 cair em duas faixas ou em nenhuma).
3) Evite duplicação de condições
Se você já garantiu um intervalo em um if, não repita a mesma checagem no próximo ramo.
// Menos claroif (renda > 2000 && renda <= 5000) { ... } else if (renda > 5000) { ... }// Mais claro (após o primeiro if, renda > 2000 já é verdade)if (renda <= 2000) { ... } else if (renda <= 5000) { ... } else { ... }Exercícios (regras de negócio simples)
Exercício 1: Faixas de imposto (com valor de fronteira)
Implemente calcularImposto com as faixas:
- Até 1500.00: 0%
- De 1500.01 até 3000.00: 8%
- De 3000.01 até 6000.00: 15%
- Acima de 6000.00: 22%
Requisitos:
- Se renda for negativa, retorne
-1para indicar erro. - Use
if/else if/elsesem aninhamento.
Exercício 2: Categoria por idade (if/else)
Crie categoria(int idade):
- idade < 0: “Inválida”
- 0 a 12: “Infantil”
- 13 a 17: “Juvenil”
- 18 a 59: “Adulto”
- 60+: “Sênior”
Requisito: use variáveis booleanas nomeadas para pelo menos duas faixas, para treinar legibilidade.
Exercício 3: Menu de console (switch)
Faça um programa que leia uma opção e imprima:
- 1: “Cadastrar”
- 2: “Listar”
- 3: “Atualizar”
- 4: “Remover”
- 0: “Sair”
- Outro: “Opção inválida”
Requisitos:
- Implemente com
switch. - Se possível no seu JDK, use
switchcomo expressão para retornar a mensagem.
Exercício 4: Ternário com critério
Crie rotuloAprovacao(double nota):
- Se nota >= 7: “Aprovado”
- Senão: “Reprovado”
Requisito: use operador ternário. Depois, reescreva com if/else e compare qual ficou mais legível para você.
Testes manuais: como validar caminhos (checklist)
Antes de automatizar testes, treine validar o controle de fluxo com uma tabela de casos. Foque em fronteiras e valores típicos.
Exemplo de tabela de testes: imposto por faixas
| Entrada (renda) | Faixa esperada | Saída esperada |
|---|---|---|
| -10.00 | Erro | -1 |
| 0.00 | 0% | 0.00 |
| 1500.00 | 0% | 0.00 |
| 1500.01 | 8% | 120.0008 |
| 3000.00 | 8% | 240.00 |
| 3000.01 | 15% | 450.0015 |
| 6000.00 | 15% | 900.00 |
| 6000.01 | 22% | 1320.0022 |
Observação: ao fazer testes manuais com double, considere formatar a saída para duas casas decimais ao imprimir, para facilitar conferência visual.
Checklist rápido
- Testei valores exatamente nos limites (ex.: 1500.00, 1500.01)?
- Testei um valor bem dentro de cada faixa?
- Existe algum valor que não cai em nenhum ramo?
- Existe algum ramo inalcançável por causa da ordem das condições?
- Em
switchtradicional, não esquecibreakquando necessário?