AFF Education Construa seu Futuro

Aula 59 — Tratamento de Erros e Desafios

Try-Catch, exceções comuns e desafios práticos com ArrayList e HashMap

O que é uma Exceção?

Uma exceção é um evento inesperado que ocorre durante a execução do programa e interrompe o fluxo normal. Sem tratamento, o programa simplesmente para e imprime uma mensagem de erro no terminal.

Exceção é o mecanismo do Java para sinalizar que algo deu errado em tempo de execução — divisão por zero, arquivo não encontrado, entrada inválida do usuário, acesso a índice inexistente, etc.

Sem tratamento, este código para abruptamente:

public class SemTratamento {
    public static void main(String[] args) {
        int[] numeros = {10, 20, 30};
        System.out.println(numeros[5]); // índice 5 não existe!
    }
}

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 3

    at SemTratamento.main(SemTratamento.java:4)

Anatomia do Try-Catch

O bloco try-catch envolve o código que pode falhar e define o que fazer quando a falha ocorrer — sem derrubar o programa.

try { código arriscado }
↓
✔ sem erro → continua normalmente
✘ exceção → vai para catch
↓
catch (TipoDeExcecao e) { tratamento }
public class AnatomiatryCatch {
    public static void main(String[] args) {
        try {
            // código que pode lançar exceção
            int resultado = 10 / 0;
            System.out.println("Resultado: " + resultado);

        } catch (ArithmeticException e) {
            // executado apenas se a exceção ocorrer
            System.out.println("Erro: " + e.getMessage());

        } finally {
            // executado SEMPRE, com ou sem exceção (opcional)
            System.out.println("Bloco finally executado.");
        }

        System.out.println("Programa continua normalmente.");
    }
}

Erro: / by zero

Bloco finally executado.

Programa continua normalmente.

💡 O bloco finally é opcional, mas quando presente é sempre executado — mesmo que o catch seja acionado. Usado normalmente para fechar arquivos, conexões ou o Scanner.

Exceções Comuns em Java

Exceção Quando ocorre Exemplo
ArithmeticException Divisão por zero int x = 5 / 0;
ArrayIndexOutOfBoundsException Índice de array inexistente arr[10] quando o array tem 3 elementos
NullPointerException Usar objeto que é null String s = null; s.length();
NumberFormatException Converter texto inválido em número Integer.parseInt("abc");
InputMismatchException Usuário digita tipo errado no Scanner Scanner esperava int, recebeu "abc"
StringIndexOutOfBoundsException Índice inválido em String "Java".charAt(10);

Múltiplos Catches

Um único try pode ter vários catch para tratar tipos diferentes de exceção:

public class MultiplosCatch {
    public static void main(String[] args) {
        String[] textos = {"42", null, "abc"};

        for (String texto : textos) {
            try {
                int numero = Integer.parseInt(texto); // pode lançar NumberFormatException ou NullPointerException
                System.out.println("Número válido: " + numero);

            } catch (NumberFormatException e) {
                System.out.println("Não é um número: \"" + texto + "\"");

            } catch (NullPointerException e) {
                System.out.println("Texto nulo — não é possível converter.");
            }
        }
    }
}

Número válido: 42

Texto nulo — não é possível converter.

Não é um número: "abc"

Protegendo Entrada do Usuário com Scanner

O erro mais comum ao usar Scanner é o usuário digitar um texto quando o programa espera um número. O InputMismatchException trata exatamente isso:

import java.util.Scanner;
import java.util.InputMismatchException;

public class EntradaSegura {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int idade = 0;
        boolean entradaValida = false;

        while (!entradaValida) {
            System.out.print("Digite sua idade: ");
            try {
                idade = sc.nextInt();
                entradaValida = true; // só chega aqui se nextInt() não lançou exceção

            } catch (InputMismatchException e) {
                System.out.println("Erro: digite apenas números inteiros.");
                sc.nextLine(); // descarta o texto inválido que ficou no buffer
            }
        }

        System.out.println("Idade registrada: " + idade);
        sc.close();
    }
}

Digite sua idade: abc

Erro: digite apenas números inteiros.

Digite sua idade: vinte

Erro: digite apenas números inteiros.

Digite sua idade: 25

Idade registrada: 25

⚠ Por que sc.nextLine() depois do catch? Quando nextInt() falha, o texto inválido permanece no buffer do Scanner. Se não for descartado com nextLine(), o próximo nextInt() lê o mesmo texto inválido de novo — criando um loop infinito.

Exemplo Completo: Cadastro de Alunos com Try-Catch

Sistema de cadastro que combina ArrayList, HashMap, Scanner e tratamento de erros. Note como o try-catch protege a leitura do menu sem derrubar o programa:

import java.util.HashMap;
import java.util.ArrayList;
import java.util.Scanner;
import java.util.InputMismatchException;

public class cadastroInterativoAlunos_ArrayList_HashMap {
    public static void main(String[] args) {
        ArrayList<HashMap<String, String>> cadastro = new ArrayList<>();
        Scanner entrada = new Scanner(System.in);

        while (true) {
            System.out.println("=== SISTEMA DE CADASTRO ===");
            System.out.println("1. Cadastrar aluno");
            System.out.println("2. Listar alunos");
            System.out.println("3. Buscar aluno");
            System.out.println("4. Sair");
            System.out.print("Escolha: ");

            int opcao;
            try {
                opcao = entrada.nextInt();
                entrada.nextLine(); // consome o "\n" que sobra do nextInt()
            } catch (InputMismatchException e) {
                System.out.println("Opção inválida. Digite um número de 1 a 4.");
                entrada.nextLine(); // descarta o texto inválido do buffer
                continue;           // volta ao início do while e exibe o menu de novo
            }

            if (opcao == 1) {
                System.out.print("Digite o nome do aluno: ");
                String nomeAluno = entrada.nextLine();
                System.out.print("Digite a matrícula do aluno: ");
                String matricula = entrada.nextLine();
                System.out.print("Digite a turma do aluno: ");
                String turma = entrada.nextLine();
                System.out.print("Digite o período do aluno: ");
                String periodo = entrada.nextLine();

                HashMap<String, String> aluno = new HashMap<>();
                aluno.put("nome",      nomeAluno);
                aluno.put("matricula", matricula);
                aluno.put("turma",     turma);
                aluno.put("periodo",   periodo);
                cadastro.add(aluno);
                System.out.println("Aluno cadastrado com sucesso!");

            } else if (opcao == 2) {
                if (cadastro.isEmpty()) {
                    System.out.println("Nenhum aluno cadastrado.");
                } else {
                    System.out.println("Cadastro de Alunos:");
                    for (HashMap<String, String> aluno : cadastro) {
                        System.out.println("Nome: "      + aluno.get("nome")
                                + " | Matrícula: "       + aluno.get("matricula")
                                + " | Turma: "           + aluno.get("turma")
                                + " | Período: "         + aluno.get("periodo"));
                    }
                }

            } else if (opcao == 3) {
                System.out.print("Digite o nome do aluno a buscar: ");
                String busca = entrada.nextLine();
                boolean encontrado = false;
                for (HashMap<String, String> aluno : cadastro) {
                    if (aluno.get("nome").equalsIgnoreCase(busca)) {
                        System.out.println("Nome: "      + aluno.get("nome")
                                + " | Matrícula: "       + aluno.get("matricula")
                                + " | Turma: "           + aluno.get("turma")
                                + " | Período: "         + aluno.get("periodo"));
                        encontrado = true;
                    }
                }
                if (!encontrado) {
                    System.out.println("Aluno não encontrado.");
                }

            } else if (opcao == 4) {
                System.out.println("Encerrando...");
                break;

            } else {
                System.out.println("Opção inválida. Digite um número de 1 a 4.");
            }
        }

        entrada.close();
    }
}

=== SISTEMA DE CADASTRO ===

1. Cadastrar aluno

2. Listar alunos

3. Buscar aluno

4. Sair

Escolha: menu

Opção inválida. Digite um número de 1 a 4.

=== SISTEMA DE CADASTRO ===

1. Cadastrar aluno

2. Listar alunos

3. Buscar aluno

4. Sair

Escolha: 1

Digite o nome do aluno: Ana Silva

Digite a matrícula do aluno: 2024001

Digite a turma do aluno: CC-03

Digite o período do aluno: 3º

Aluno cadastrado com sucesso!

Por que o continue depois do catch? O continue pula o restante do corpo do while e volta imediatamente ao início — exibindo o menu de novo. Sem ele, o código continuaria tentando executar os if/else com uma variável opcao não inicializada.

Desafios

🏆 Desafio 1 — Divisão Segura com Try-Catch

Escreva um programa que leia dois números inteiros do teclado e exiba o resultado da divisão. Use try-catch para tratar dois erros possíveis:

O programa deve continuar pedindo os números até que uma divisão válida seja realizada.

import java.util.Scanner;
import java.util.InputMismatchException;

public class DivisaoSegura {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        while (true) {
            try {
                System.out.print("Digite o dividendo: ");
                int dividendo = sc.nextInt();

                System.out.print("Digite o divisor: ");
                int divisor = sc.nextInt();

                int resultado = dividendo / divisor; // lança ArithmeticException se divisor == 0
                System.out.println("Resultado: " + dividendo + " / " + divisor + " = " + resultado);
                break; // divisão válida — encerra o loop

            } catch (ArithmeticException e) {
                System.out.println("Erro: divisão por zero não é permitida.");
                sc.nextLine();

            } catch (InputMismatchException e) {
                System.out.println("Erro: digite apenas números inteiros.");
                sc.nextLine(); // descarta o texto inválido do buffer
            }
        }

        sc.close();
    }
}

Digite o dividendo: dez

Erro: digite apenas números inteiros.

Digite o dividendo: 10

Digite o divisor: 0

Erro: divisão por zero não é permitida.

Digite o dividendo: 10

Digite o divisor: 3

Resultado: 10 / 3 = 3

🏆 Desafio 2 — Acesso Seguro a Array com Try-Catch

Dado o array abaixo, escreva um programa que:

String[] cidades = {"Natal", "Recife", "Fortaleza", "João Pessoa", "Maceió"};
import java.util.Scanner;
import java.util.InputMismatchException;

public class AcessoSeguroArray {
    public static void main(String[] args) {
        String[] cidades = {"Natal", "Recife", "Fortaleza", "João Pessoa", "Maceió"};
        Scanner sc = new Scanner(System.in);

        System.out.println("O array tem " + cidades.length + " cidades (índices 0 a " + (cidades.length - 1) + ").");

        while (true) {
            System.out.print("Digite um índice: ");
            try {
                int idx = sc.nextInt();
                System.out.println("Cidade encontrada: " + cidades[idx]); // lança ArrayIndexOutOfBoundsException se inválido
                break;

            } catch (ArrayIndexOutOfBoundsException e) {
                System.out.println("Índice inválido. Escolha entre 0 e " + (cidades.length - 1) + ".");

            } catch (InputMismatchException e) {
                System.out.println("Digite apenas números inteiros.");
                sc.nextLine();
            }
        }

        sc.close();
    }
}

O array tem 5 cidades (índices 0 a 4).

Digite um índice: 10

Índice inválido. Escolha entre 0 e 4.

Digite um índice: -1

Índice inválido. Escolha entre 0 e 4.

Digite um índice: 2

Cidade encontrada: Fortaleza

🏆 Desafio 3 — Lista de Compras com Preço Total

Crie uma lista de compras usando ArrayList<HashMap<String, String>> com pelo menos 5 produtos (nome e preço). Em seguida:

import java.util.ArrayList;
import java.util.HashMap;

public class ListaCompras {
    public static void main(String[] args) {
        ArrayList<HashMap<String, String>> compras = new ArrayList<>();

        String[][] itens = {
            {"Arroz 5kg",   "28.90"},
            {"Feijão 1kg",  "9.50"},
            {"Frango 2kg",  "32.00"},
            {"Queijo 500g", "22.00"},
            {"Detergente",  "4.80"},
            {"Sabão em pó", "18.50"},
            {"Café 500g",   "15.00"},
            {"Shampoo",     "24.99"},
            {"Leite 1L",    "7.50"},
            {"Macarrão",    "6.90"}
        };

        for (String[] item : itens) {
            HashMap<String, String> produto = new HashMap<>();
            produto.put("nome",  item[0]);
            produto.put("preco", item[1]);
            compras.add(produto);
        }

        // Exibindo todos
        System.out.println("=== LISTA DE COMPRAS ===");
        double total = 0;
        for (HashMap<String, String> p : compras) {
            double preco = Double.parseDouble(p.get("preco"));
            System.out.printf("%-15s R$ %.2f%n", p.get("nome"), preco);
            total += preco;
        }
        System.out.printf("TOTAL: R$ %.2f%n", total);

        // Produtos acima de R$ 50 — nenhum neste exemplo, mas a lógica está correta
        System.out.println("Produtos acima de R$ 20,00:");
        for (HashMap<String, String> p : compras) {
            if (Double.parseDouble(p.get("preco")) > 20.00) {
                System.out.println("- " + p.get("nome"));
            }
        }
    }
}

=== LISTA DE COMPRAS ===

Arroz 5kg R$ 28.90

Feijão 1kg R$ 9.50

Frango 2kg R$ 32.00

Queijo 500g R$ 22.00

Detergente R$ 4.80

Sabão em pó R$ 18.50

Café 500g R$ 15.00

Shampoo R$ 24.99

Leite 1L R$ 7.50

Macarrão R$ 6.90

TOTAL: R$ 170.09

Produtos acima de R$ 20,00:

- Arroz 5kg

- Frango 2kg

- Queijo 500g

- Shampoo

🏆 Desafio 4 — Estoque com Busca e Atualização

Crie um ArrayList<HashMap<String, String>> representando um estoque com pelo menos 4 produtos (nome, quantidade, preço). Implemente:

import java.util.ArrayList;
import java.util.HashMap;

public class Estoque {
    public static void main(String[] args) {
        ArrayList<HashMap<String, String>> estoque = new ArrayList<>();

        String[][] dados = {
            {"Notebook",  "15", "3500.00"},
            {"Mouse",     "40", "80.00"},
            {"Teclado",   "25", "150.00"},
            {"Monitor",   "10", "900.00"}
        };

        for (String[] d : dados) {
            HashMap<String, String> p = new HashMap<>();
            p.put("nome",       d[0]);
            p.put("quantidade", d[1]);
            p.put("preco",      d[2]);
            estoque.add(p);
        }

        // Exibir estoque inicial
        System.out.println("=== ESTOQUE INICIAL ===");
        for (HashMap<String, String> p : estoque) {
            System.out.printf("%-12s Qtd: %-5s Preço: R$ %s%n",
                p.get("nome"), p.get("quantidade"), p.get("preco"));
        }

        // Buscar produto
        String busca = "Mouse";
        System.out.println("\nBuscando: " + busca);
        for (HashMap<String, String> p : estoque) {
            if (p.get("nome").equalsIgnoreCase(busca)) {
                System.out.println("Encontrado — Quantidade atual: " + p.get("quantidade"));
            }
        }

        // Atualizar quantidade do Mouse
        for (HashMap<String, String> p : estoque) {
            if (p.get("nome").equalsIgnoreCase("Mouse")) {
                p.put("quantidade", "55");
                System.out.println("Quantidade do Mouse atualizada para 55.");
            }
        }

        // Estoque atualizado
        System.out.println("\n=== ESTOQUE ATUALIZADO ===");
        for (HashMap<String, String> p : estoque) {
            System.out.printf("%-12s Qtd: %-5s Preço: R$ %s%n",
                p.get("nome"), p.get("quantidade"), p.get("preco"));
        }
    }
}

=== ESTOQUE INICIAL ===

Notebook Qtd: 15 Preço: R$ 3500.00

Mouse Qtd: 40 Preço: R$ 80.00

Teclado Qtd: 25 Preço: R$ 150.00

Monitor Qtd: 10 Preço: R$ 900.00

Buscando: Mouse

Encontrado — Quantidade atual: 40

Quantidade do Mouse atualizada para 55.

=== ESTOQUE ATUALIZADO ===

Notebook Qtd: 15 Preço: R$ 3500.00

Mouse Qtd: 55 Preço: R$ 80.00

Teclado Qtd: 25 Preço: R$ 150.00

Monitor Qtd: 10 Preço: R$ 900.00

Exercícios

Questões práticas sobre try-catch e tratamento de exceções:

1. O que acontece se uma exceção é lançada dentro do bloco try e há um catch compatível?

2. Por que é necessário chamar sc.nextLine() dentro do catch de um InputMismatchException?

3. Qual exceção o Java lança ao tentar executar int x = 10 / 0;?

4. O bloco finally é executado:

5. O que o continue faz dentro de um while, no contexto do menu de cadastro?

6. Qual exceção é lançada ao tentar acessar arr[10] em um array de 3 elementos?

Exercícios de Aplicação AFF Education

Reforce o conteúdo desta aula com mais dois exercícios práticos:

1. Qual estrutura captura e trata um erro em tempo de execução em Java?

2. Acessar uma chave inexistente em um HashMap com get retorna: