AFF Education Construa seu Futuro

Aula 63 - Projeto Final: Sistema de Biblioteca

Aplicação completa integrando os conceitos do curso

Sobre este Projeto

Parabéns por chegar até aqui! Nas próximas três aulas você vai colocar em prática tudo que aprendeu no curso construindo aplicações reais que rodam no seu computador.

Nesta aula, vamos construir um Sistema de Gerenciamento de Biblioteca. O programa permite cadastrar livros, buscar por título ou ISBN, emprestar, devolver e listar o acervo completo — tudo via terminal, com interação real do usuário.

Como rodar no VSCode: Crie um arquivo chamado Biblioteca.java, cole o código completo, abra o terminal integrado do VSCode (Ctrl + `) e execute com javac Biblioteca.java seguido de java Biblioteca.

Conceitos Aplicados Neste Projeto

Antes de ver o código, veja quais aulas do curso estão sendo usadas aqui:

Conceito Onde aparece no projeto Aulas relacionadas
Classe e objetos A classe Livro modela cada livro do acervo Aulas 64–65
ArrayList ArrayList<Livro> armazena o acervo dinamicamente Aulas 57–59
HashMap HashMap<String, Livro> permite busca rápida por ISBN Aulas 60–61
Scanner Lê todas as entradas do usuário no menu Aula 17
Métodos personalizados cadastrar(), buscar(), emprestar(), devolver(), listar() Aulas 34, 48
Loop do-while Mantém o menu ativo até o usuário escolher sair Aula 42
Switch-case Direciona a opção escolhida no menu para o método correto Aula 45
For-each Percorre o acervo para listar e buscar livros Aula 47
boolean Campo disponivel controla se o livro está emprestado Aula 06
Métodos de String .toLowerCase() torna a busca por título insensível a maiúsculas Aula 35

Estrutura: A Classe Livro

O primeiro passo é modelar o que é um livro no nosso sistema. Cada livro tem quatro informações: título, autor, ISBN e disponibilidade. Isso vai para dentro de uma classe:

// A classe Livro representa um único livro do acervo
class Livro {
    String titulo;
    String autor;
    String isbn;
    boolean disponivel;

    // Construtor: recebe os dados e cria o objeto
    Livro(String titulo, String autor, String isbn) {
        this.titulo    = titulo;
        this.autor     = autor;
        this.isbn      = isbn;
        this.disponivel = true; // Todo livro começa disponível
    }
}

O que é this? Dentro do construtor, this.titulo se refere ao campo do objeto, enquanto titulo sozinho se refere ao parâmetro recebido. O this elimina a ambiguidade quando os nomes são iguais.

Código Completo — Biblioteca.java

Cole este código inteiro em um arquivo chamado Biblioteca.java. Cada seção está comentada para facilitar a leitura:

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

// ─── Classe que modela um livro ────────────────────────────────────────────
class Livro {
    String titulo;
    String autor;
    String isbn;
    boolean disponivel;

    Livro(String titulo, String autor, String isbn) {
        this.titulo     = titulo;
        this.autor      = autor;
        this.isbn       = isbn;
        this.disponivel = true;
    }
}

// ─── Classe principal ─────────────────────────────────────────────────────
public class Biblioteca {

    // Acervo: lista dinâmica de livros
    static ArrayList<Livro> acervo = new ArrayList<>();

    // Índice rápido: ISBN → Livro
    static HashMap<String, Livro> indiceIsbn = new HashMap<>();

    static Scanner sc = new Scanner(System.in);

    // ── MÉTODO PRINCIPAL ────────────────────────────────────────────────────
    public static void main(String[] args) {

        // Popula o acervo com alguns livros iniciais
        cadastrar("O Hobbit",              "J.R.R. Tolkien",   "978-0261102217");
        cadastrar("Dom Casmurro",          "Machado de Assis", "978-8535910902");
        cadastrar("Clean Code",            "Robert C. Martin", "978-0132350884");
        cadastrar("O Alquimista",          "Paulo Coelho",     "978-8531608087");
        cadastrar("Algoritmos em Java",    "Robert Sedgewick", "978-0201361209");

        int opcao;

        do {
            exibirMenu();
            opcao = Integer.parseInt(sc.nextLine().trim());

            switch (opcao) {
                case 1: menuCadastrar();  break;
                case 2: menuBuscar();     break;
                case 3: menuEmprestar();  break;
                case 4: menuDevolver();   break;
                case 5: listar();         break;
                case 0:
                    System.out.println("\nAté logo! Biblioteca encerrada.");
                    break;
                default:
                    System.out.println("Opção inválida. Tente novamente.");
            }

        } while (opcao != 0);

        sc.close();
    }

    // ── MENU ────────────────────────────────────────────────────────────────
    static void exibirMenu() {
        System.out.println("\n╔══════════════════════════════╗");
        System.out.println("║      SISTEMA DE BIBLIOTECA   ║");
        System.out.println("╠══════════════════════════════╣");
        System.out.println("║  1. Cadastrar livro          ║");
        System.out.println("║  2. Buscar livro             ║");
        System.out.println("║  3. Emprestar livro          ║");
        System.out.println("║  4. Devolver livro           ║");
        System.out.println("║  5. Listar acervo            ║");
        System.out.println("║  0. Sair                     ║");
        System.out.println("╚══════════════════════════════╝");
        System.out.print("Escolha uma opção: ");
    }

    // ── CADASTRAR ────────────────────────────────────────────────────────────
    static void cadastrar(String titulo, String autor, String isbn) {
        if (indiceIsbn.containsKey(isbn)) {
            System.out.println("ISBN já cadastrado: " + isbn);
            return;
        }
        Livro novo = new Livro(titulo, autor, isbn);
        acervo.add(novo);
        indiceIsbn.put(isbn, novo);
    }

    static void menuCadastrar() {
        System.out.print("Título  : "); String titulo = sc.nextLine();
        System.out.print("Autor   : "); String autor  = sc.nextLine();
        System.out.print("ISBN    : "); String isbn   = sc.nextLine();
        cadastrar(titulo, autor, isbn);
        System.out.println("✓ Livro cadastrado com sucesso!");
    }

    // ── BUSCAR ───────────────────────────────────────────────────────────────
    static void menuBuscar() {
        System.out.println("Buscar por: 1) Título   2) ISBN");
        System.out.print("Opção: ");
        String op = sc.nextLine().trim();

        if (op.equals("1")) {
            System.out.print("Digite parte do título: ");
            String trecho = sc.nextLine().toLowerCase();
            boolean encontrou = false;

            // For-each percorre todo o acervo
            for (Livro livro : acervo) {
                if (livro.titulo.toLowerCase().contains(trecho)) {
                    imprimirLivro(livro);
                    encontrou = true;
                }
            }
            if (!encontrou) System.out.println("Nenhum livro encontrado.");

        } else {
            System.out.print("Digite o ISBN: ");
            String isbn = sc.nextLine().trim();
            Livro livro = indiceIsbn.get(isbn);
            if (livro != null) imprimirLivro(livro);
            else System.out.println("ISBN não encontrado.");
        }
    }

    // ── EMPRESTAR ────────────────────────────────────────────────────────────
    static void menuEmprestar() {
        System.out.print("ISBN do livro para emprestar: ");
        String isbn = sc.nextLine().trim();
        Livro livro = indiceIsbn.get(isbn);

        if (livro == null) {
            System.out.println("Livro não encontrado.");
        } else if (!livro.disponivel) {
            System.out.println("Este livro já está emprestado.");
        } else {
            livro.disponivel = false;
            System.out.println("✓ \"" + livro.titulo + "\" emprestado com sucesso!");
        }
    }

    // ── DEVOLVER ─────────────────────────────────────────────────────────────
    static void menuDevolver() {
        System.out.print("ISBN do livro para devolver: ");
        String isbn = sc.nextLine().trim();
        Livro livro = indiceIsbn.get(isbn);

        if (livro == null) {
            System.out.println("Livro não encontrado.");
        } else if (livro.disponivel) {
            System.out.println("Este livro não estava emprestado.");
        } else {
            livro.disponivel = true;
            System.out.println("✓ \"" + livro.titulo + "\" devolvido. Disponível novamente!");
        }
    }

    // ── LISTAR ACERVO ────────────────────────────────────────────────────────
    static void listar() {
        System.out.println("\n── ACERVO COMPLETO (" + acervo.size() + " livros) ──");
        int disponiveis = 0;

        for (Livro livro : acervo) {
            imprimirLivro(livro);
            if (livro.disponivel) disponiveis++;
        }

        System.out.println("\nDisponíveis : " + disponiveis);
        System.out.println("Emprestados : " + (acervo.size() - disponiveis));
    }

    // ── AUXILIAR: imprime um livro formatado ─────────────────────────────────
    static void imprimirLivro(Livro livro) {
        String status = livro.disponivel ? "✓ Disponível" : "✗ Emprestado";
        System.out.println("────────────────────────────────");
        System.out.println("Título : " + livro.titulo);
        System.out.println("Autor  : " + livro.autor);
        System.out.println("ISBN   : " + livro.isbn);
        System.out.println("Status : " + status);
    }
}

╔══════════════════════════════╗

║ SISTEMA DE BIBLIOTECA ║

╠══════════════════════════════╣

║ 1. Cadastrar livro ║

║ 2. Buscar livro ║

║ 3. Emprestar livro ║

║ 4. Devolver livro ║

║ 5. Listar acervo ║

║ 0. Sair ║

╚══════════════════════════════╝

Escolha uma opção: 3

ISBN do livro para emprestar: 978-0261102217

✓ "O Hobbit" emprestado com sucesso!

Escolha uma opção: 5

── ACERVO COMPLETO (5 livros) ──

────────────────────────────────

Título : O Hobbit

Autor : J.R.R. Tolkien

ISBN : 978-0261102217

Status : ✗ Emprestado

────────────────────────────────

Título : Dom Casmurro

Autor : Machado de Assis

ISBN : 978-8535910902

Status : ✓ Disponível

...

Disponíveis : 4

Emprestados : 1

Dica de extensão: Para ir além, tente adicionar uma funcionalidade de histórico de empréstimos usando outro ArrayList<String> que registra o título e a data de cada empréstimo com LocalDate.now().

Revisão dos Conceitos-Chave

🔑 HashMap — busca em O(1)

Ao guardar cada livro também no HashMap com o ISBN como chave, a busca por ISBN é instantânea — não importa se o acervo tem 10 ou 10.000 livros. Sem o HashMap, seria necessário percorrer toda a lista a cada busca.

🔄 do-while no menu

O menu usa do-while em vez de while porque precisamos exibir o menu pelo menos uma vez antes de verificar se o usuário quer sair. Com while comum, seria necessário ler a opção antes do loop — duplicando código.

📦 static nos métodos

Todos os métodos são static porque pertencem à classe e não a um objeto específico. Como o main também é estático, ele só consegue chamar diretamente outros métodos estáticos.

🔡 .toLowerCase() na busca

Ao converter o título do livro e o termo buscado para minúsculas antes de comparar, a busca funciona independente de como o usuário digita: "hobbit", "Hobbit" e "HOBBIT" encontram o mesmo livro.

✅ Separação de responsabilidades: Cada método faz exatamente uma coisa. cadastrar() cadastra, listar() lista, imprimirLivro() formata a saída. Isso é o primeiro passo para um código profissional e fácil de manter.

Exercícios

Teste sua compreensão do projeto Biblioteca:

1. Por que usamos um HashMap além do ArrayList neste projeto?

2. O que acontece com o campo disponivel quando um livro é emprestado?

3. Por que o menu principal usa do-while e não while?

4. O que faz o método .toLowerCase() na busca por título?

5. Qual estrutura de dados seria mais adequada para guardar o histórico de todos os empréstimos realizados?

6. O construtor da classe Livro recebe 3 parâmetros mas define 4 campos. Qual campo não vem do construtor e por quê?

Exercícios de Aplicação AFF Education

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

1. Em um sistema de biblioteca, qual estrutura é mais adequada para guardar uma coleção crescente de livros?

2. Para representar um livro com título, autor e ano, a melhor abordagem orientada a objetos é: