Contador que que não funciona para um mini sistema de biblioteca

Fala galera!!! essa é a minha primeira pergunta então talvez não fique muito claro mas enfim.

Eu sou iniciante no JAVA (3 meses de estudo) e estou tendo um problema com um contador basicamente eu estou fazendo um mini sistema pra uma biblioteca e eu preciso por um limite de no máximo 3 livros alugados caso eles sejam alugados então o usuário precisa devolver um livro

meu código está dividido em três partes a Main (que é uma interface conectando o usuário e a funcionário), o problema esta no método alugar livro (classe MAIN) e a contagem que esta sendo feita na classe Funcionário. Eu tbm aceito criticas ao meu código! Obrigado pela atenção.

Essa é a MAIN:
import java.util.ArrayList;
import java.util.Scanner;

public interface Main {
static ArrayList livros = new ArrayList();
static ArrayList usuarios = new ArrayList();
Scanner scanner = new Scanner(System.in);
public static void main(String[] args) {
while (true) {
System.out.println(“== Biblioteca ==”);
System.out.println(“1 - Entrar”);
System.out.println(“2 - Registrar-se”);
System.out.println(“3 - Listar Usuarios”);
System.out.println(“4 - Adiconario Livro”);
System.out.println(“5 - Listar Livro”);
System.out.println(“6 - Alugar Livro”);
System.out.println(“7 - Devolver Livro”);
System.out.println(“0 - Sair”);
int opcao = scanner.nextInt();
switch (opcao) {
case 1:
entrar();
break;
case 2:
registrarse();
break;
case 3:
listarUsuarios();
break;
case 4:
adicionarLivro();
break;
case 5:
listarLivros();
break;
case 6:
alugarLivro();
break;
case 7:
devolverLivro();
break;
case 0:
System.out.println(“saindo…”);
}
}
}

static void entrar() {
	if (usuarios.isEmpty()) {
		System.out.println("Usuario não encontrado. Deseja registrar-se? S/N");
		String opcao = scanner.next();
		if (opcao.equalsIgnoreCase("Sim") || opcao.equalsIgnoreCase("S")) {
			registrarse();
		} else if (opcao.equalsIgnoreCase("nao") || opcao.equalsIgnoreCase("N") || opcao.equalsIgnoreCase("não")) {

		}
	} 
	else if (!usuarios.isEmpty()) {
		System.out.print("Digite seu nome: ");
		String existeNome = scanner.next();
		System.out.print("Digite seu cpf: ");
		String existeCpf = scanner.next();
		for (Usuario u : usuarios) {
			if (u.getNome().equals(existeNome) && u.getCpf().equals(existeCpf)) {
				System.out.println("Você entrou com sucesso");

			} else {
				System.out.println("usuario não encontrado tente novamente!");
				return;
			}
		}
	}
}

static void registrarse() {
	Usuario u = new Usuario(scanner);
	usuarios.add(u);
	System.out.println("Registrado com sucesso!");
}

static void listarUsuarios() {
	System.out.println("Digite a senha da biblioteca");
	String entrar = scanner.next();
	if (entrar.equals("Biblioteca123")) {
		for (Usuario encontrados : usuarios) {
			System.out.println(encontrados);
		}
	} else if (!entrar.equals("Biblioteca123")) {

	}
}
static void adicionarLivro() {
	while (true) {
		System.out.println("Digite a senha da biblioteca");
		String entrar = scanner.next();

		if (entrar.equals("Biblioteca123")) {
			Funcionario l = new Funcionario(scanner);
			livros.add(l);
			l.setAlugado(false);
			System.out.println("Deseja adicionar mais livros? S/N");
			String opcao = scanner.next();
			if (opcao.equalsIgnoreCase("Sim") || opcao.equalsIgnoreCase("S")) {

			} else if (opcao.equalsIgnoreCase("nao") || opcao.equalsIgnoreCase("N")
					|| opcao.equalsIgnoreCase("não")) {
				break;
			}
		}
	}
}

static void listarLivros() {
	for (Funcionario a : livros) {
		System.out.println(a);
	}
}

static void alugarLivro() {
	if (usuarios.isEmpty()) {
		System.out.println("Você precisar se cadastrar! deseja se cadastrar? S/N");
		String opcao = scanner.next();
		if (opcao.equalsIgnoreCase("Sim") || opcao.equalsIgnoreCase("S")) {
			registrarse();
		} else if (opcao.equalsIgnoreCase("nao") || opcao.equalsIgnoreCase("N") || opcao.equalsIgnoreCase("não")) {
			return;
		}
	}
	if (!usuarios.isEmpty())
		System.out.print("Digite a isbn do livro:");
	String ISBN = scanner.next();
	for (Funcionario livro : livros) {
		if (livro.getIsbn().contains(ISBN) && livro.isAlugado() == true) {
			System.out.println("Este livro ja foi alugado!");
			}
		if(livro.getIsbn().contains(ISBN) && livro.getContagem() > 3) {
			System.out.println("Você ja alcançou o maximo de livro deseja devolver algum livro? S/N");
			String opcao = scanner.next();
			if (opcao.equalsIgnoreCase("Sim") || opcao.equalsIgnoreCase("S")) {
				registrarse();
			} else if (opcao.equalsIgnoreCase("nao") || opcao.equalsIgnoreCase("N") || opcao.equalsIgnoreCase("não")) {
				break;
			}
		}
		else if (livro.getIsbn().equals(ISBN) && livro.isAlugado() == false) {
			System.out.println("Livro alugado!");
			livro.setAlugado(true);
			livro.contagem();
			System.out.println(livro.getContagem());
			break;
		}
	}

}

static void devolverLivro() {
	System.out.print("Digite a isbn do livro: ");
	String isbn = scanner.next();
	for (Funcionario livro : livros) {
		if (livro.getIsbn().equals(isbn) && livro.isAlugado() == false) {
			System.out.println("Este livro ja foi devolvido");
			break;
		} else if (livro.getIsbn().equals(isbn)) {
			System.out.println("Livro devolvido!");
			livro.setAlugado(false);
			break;
		}
	}
}

ESSA É A USUARIO :
import java.util.Scanner;
public class Usuario implements Main{
String nome;
String cpf;

Scanner scanner = new Scanner(System.in);

@Override
public String toString() {
	return "nome:" + nome + ", cpf:" + cpf;
}
Usuario(Scanner scanner) {
		System.out.print("Digite seu nome: ");
		this.nome = scanner.next();
		System.out.print("Digite seu cpf: ");
		this.cpf = scanner.next();
}

public String getNome() {
	return nome;
}
public String getCpf() {
	return cpf;
}

}

ESSA É A FUNCIONARIO
import java.util.Scanner;
public class Funcionario implements Main{

static Scanner scanner = new Scanner(System.in);
private String titulo;
private String Autor;
private String isbn;
private int ano;
private boolean alugado;
int contagem;
@Override
public String toString() {
	if(alugado) {																					
		return "titulo:" + titulo + ", Autor:" + Autor + ", isbn:" + isbn + ", ano:" + ano + ", indisponivel!";
	}
	if(!alugado) {																						
		return "titulo:" + titulo + ", Autor:" + Autor + ", isbn:" + isbn + ", ano:" + ano + ", disponivel!";
	}
	return titulo;
}
Funcionario(Scanner scanner){
	System.out.print("Digite o Titulo do livro: ");
	this.titulo = scanner.next();
	System.out.print("Digite o Autor do livro: ");
	this.Autor = scanner.next();
	System.out.print("Digite a isbn do livro: ");
	this.isbn = scanner.next();
	System.out.print("Digite o ano de publicação do livro: ");
	this.ano = scanner.nextInt();
	scanner.nextLine();
}	
public void contagem() {
	contagem++;
}
public int getContagem() {
	return contagem;
}
public boolean isAlugado() {
	return alugado;
}
public void setAlugado(boolean alugado) {
	this.alugado = alugado;
}
public String getTitulo() {
	return titulo;
}
public String getAutor() {
	return Autor;
}
public String getIsbn() {
	return isbn;
}
public int getAno() {
	return ano;
}

}

DESCOBRI ALGO!! na realidade ele conta apenas da ISBN de cada livro então ele esta funcionando mas não esta funcionando :smiley: kkkkkk

Porque diabos “Main” é uma interface?

Interfaces são tipos abstratos de dados e servem para definir contratos de operações que determinadas classes devem realizar.

Você criou uma interface e entupiu de metros estáticos e concretos, está errado.

3 curtidas

Além do que já foi dito (não faz sentido Main ser uma interface, e menos sentido ainda Usuario e Funcionario implementarem esta interface), tem outros detalhes aí.

Tem bastante coisa que daria para melhorar, mas para não ficar muita informação de uma vez (que pode acabar te confundindo), vou citar apenas algumas.

Pra começar, este loop:

for (Usuario u : usuarios) {
    if (u.getNome().equals(existeNome) && u.getCpf().equals(existeCpf)) {
        System.out.println("Você entrou com sucesso");

    } else {
        System.out.println("usuario não encontrado tente novamente!");
        return;
    }
}

A lógica está errada. Vamos supor que a lista usuarios tem 2 usuários: o primeiro tem nome “Fulano” e CPF “12345678909”, o segundo tem nome “Ciclano” e CPF “11122233396”.

Suponha que foi digitado “Ciclano” e “11122233396” (são os respectivos valores de existeNome e existeCpf). Ou seja, é um usuário que deveria ser encontrado.

Só que na primeira iteração do loop vai entrar no else, vai imprimir que não foi encontrado e o return encerra a execução do método. Ou seja, também vai interromper o for, e ele não vai ter a chance de verificar o segundo elemento, que seria o usuário correto.


O certo seria ir verificando os usuários, até encontrar algum:

// indica se conseguiu entrar (começa com "não")
boolean entrou = false;
for (Usuario u : usuarios) {
    if (u.getNome().equals(existeNome) && u.getCpf().equals(existeCpf)) {
        entrou = true;
        // encontrei, pode interromper o loop
        break;
    }
}

// só depois que o loop terminou, verifica se encontrou ou não
if (entrou) {
    System.out.println("Você entrou com sucesso");
} else {
    System.out.println("usuario não encontrado tente novamente!");
}

Ou seja, se eu encontrar o usuário, aí sim eu interrompo o loop usando break (não usei return porque isso interrompe o método inteiro, e ele não executaria o código que está depois do for).

E só depois do for eu verifico se encontrou ou não, e imprimo a mensagem correspondente.


Por fim, só mais uma coisa. Neste método tem o seguinte:

if (usuarios.isEmpty()) {
    // faz uma coisa
} else if (!usuarios.isEmpty()) {
    // faz outra coisa
}

Só que neste caso, o método isEmpty() retorna um boolean. Ou seja, ele tem apenas dois retornos possíveis: true ou false. Então se não entrou no if é porque não é true, portanto a única opção restante é false e por isso não precisa verificar no else, é redundante.

Poderia ser apenas assim:

if (usuarios.isEmpty()) {
    // faz uma coisa
} else {
    // faz outra coisa
}

Ou seja, se isEmpty() retorna true, entra no if. Se não entrou no if é porque não retornou true, mas como é um boolean a única possibilidade é que retornou false, então não precisa verificar if (!usuarios.isEmpty()) no else.


Obs: na verdade eu faria o método entrar() retornar true ou false:

// retorna um boolean indicando se conseguiu entrar
static boolean entrar() {
    // ...

    for (Usuario u : usuarios) {
        if (u.getNome().equals(existeNome) && u.getCpf().equals(existeCpf)) {
            // encontrei, posso retornar direto
            return true;
        }
    }
    // se chegou aqui é porque percorreu todos os usuários e não encontrou
    return false;
}

E quem chama o método faz o que precisar com o resultado (como imprimir mensagens, etc).

if (entrar()) {
    System.out.println("Você entrou com sucesso");
} else {
    System.out.println("usuario não encontrado tente novamente!");
}

Além disso, a parte do cadastro eu acho que deveria ficar fora, pois o método que verifica se o usuário está cadastrado não deveria ser responsável por também chamar o registro. Mas aí já começa a alterar demais o código, e como já dito, acho que fica informação demais e pode acabar te confundindo.


Mas só pra finalizar, não faz sentido um funcionário ter título, autor e ISBN. Será que esta classe não deveria se chamar Livro?

1 curtida

Ah, outra dica rápida é usar sempre scanner.nextLine() ao ler dados do teclado. Tem vários posts no fórum que explicam o motivo, mas - só pra fazer uma propagandinha - eu escrevi um post bem detalhado sobre isso:

1 curtida

eu realmente não sei pq eu fiz isso :no_mouth:? Mas eu arrumei essa parte e dividi em duas classes uma main e uma biblioteca, ai na main eu faço os códigos dos metodos e na biblioteca eu apenas chamo os metodos acho que a leitura do código fica melhor né ?

Nossa! eu realmente não estava considerando usar o scanner.nextLine() em nenhum momento do meu código mas depois de ler esse artigo vou começas a usar mais.(vou logo trocar meus scanner.next() kkkkk) Valeu pela ajuda!

Complementando…

Em termos de organização das classes, eu faria diferente:

  • manter a classe Usuario
  • mudar o nome da classe Funcionario para Livro, já que esta classe tem título, autor, ISBN, ou seja, todos os dados de um livro
  • criar a classe Biblioteca, que contém um registro de usuários e respectivos livros alugados, além dos livros disponíveis

Assim, quem sabe se um livro está alugado ou não é a biblioteca (e não o livro). Além disso, pode existir mais de um exemplar do livro, não? E pra alugar e devolver, precisa saber também qual o usuário que está fazendo isso.


Para o usuário e livro, usei record, que é um recurso introduzido no Java 16 (apesar de ser possível usar no Java 14 e 15 como preview). Fica assim:

Arquivo Usuario.java:

public record Usuario(String nome, String cpf) {}

Arquivo Livro.java:

public record Livro(String titulo, String autor, String isbn, int ano) {}

Nada impede que vc use classes normais com construtor, getters, etc. É que o record cria tudo isso automaticamente, incluindo os métodos equals e hashCode que são importantes para adicionarmos estas classes em maps (que será feito na classe Biblioteca abaixo).

Como está aprendendo, eu sugiro já começar com versões mais recentes da linguagem, até para ir se acostumando com os novos recursos, como os records.


Enfim, a lógica de quais livros estão alugados para quais usuários fica a cargo da biblioteca.

Arquivo Biblioteca.java:

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.stream.Collectors;

public class Biblioteca {
    // registro de usuários e os respectivos livros que estão alugados
    private Map<Usuario, List<Livro>> registro;
    // catálogo dos livros disponíveis e suas respectivas quantidades (pode ter mais de um exemplar de cada livro)
    private Map<Livro, Integer> catalogo;
    // quantidade máxima de livros que cada usuário pode ter por vez
    private int maxLivrosPorUsuario;
    private Scanner scanner;

    public Biblioteca(int maxLivrosPorUsuario, Scanner scanner) {
        this.registro = new HashMap<>();
        this.catalogo = new HashMap<>();
        this.maxLivrosPorUsuario = maxLivrosPorUsuario;
        this.scanner = scanner;
    }

    // mostra o status atual
    public void status() {
        System.out.println("Catálogo:");
        for (var e : this.catalogo.entrySet()) {
            System.out.println("- " + e.getValue() + " unidade(s) de '" + e.getKey().titulo() + "'");
        }
        System.out.println("\n\nLivros alugados:");
        for (var e : this.registro.entrySet()) {
            System.out.println("- " + e.getKey().nome() + " -> " + e.getValue().stream().map(Livro::titulo).collect(Collectors.joining(", ")));
        }
    }

    public void registrar(Usuario usuario) {
        if (this.registro.containsKey(usuario)) {
            System.out.println("Usuário já está cadastrado");
        } else {
            this.registro.put(usuario, new ArrayList<>());
        }
    }

    public void listarUsuarios() {
        for (Usuario usuario : this.registro.keySet()) {
            System.out.println(usuario);
        }
    }

    public void adicionarLivro(Livro livro) {
        // Se o livro já existe no catálogo, incrementa a quantidade. Senão adiciona ao catálogo
        this.atualizarCatalogo(livro, 1);
    }

    private void atualizarCatalogo(Livro livro, int qtd) {
        this.catalogo.put(livro, this.catalogo.getOrDefault(livro, 0) + qtd);
    }

    public void alugar(Usuario usuario, Livro livro) {
        if (!this.registro.containsKey(usuario)) {
            System.out.println("Usuário não cadastrado");
            return;
        }
        if (this.catalogo.get(livro) == 0) {
            System.out.println("Livro não está disponível para alugar");
            return;
        }

        List<Livro> alugados = this.registro.get(usuario);
        if (alugados.size() == this.maxLivrosPorUsuario) {
            if (this.simOuNao("Você ja alcançou o máximo de livros, deseja devolver algum livro?")) {
                if (!this.devolucaoEscolha(alugados)) {
                    System.out.println("Você optou por não devolver, então não poderá alugar outro livro");
                    return;
                }
            } else {
                System.out.println("Você optou por não devolver, então não poderá alugar outro livro");
                return;
            }
        }

        alugados.add(livro);
        // diminui a quantidade disponível no catálogo
        this.atualizarCatalogo(livro, -1);
    }

    public void devolver(Usuario usuario, Livro livro) {
        if (!this.registro.containsKey(usuario)) {
            System.out.println("Usuário não cadastrado");
            return;
        }

        this.devolucao(this.registro.get(usuario), livro);
    }

    private void devolucao(List<Livro> list, Livro livro) {
        if (list.remove(livro)) {
            this.atualizarCatalogo(livro, 1);
            System.out.println("Livro devolvido: " + livro);
        } else {
            System.out.println("Livro não estava alugado para este usuário");
        }
    }

    private boolean devolucaoEscolha(List<Livro> alugados) {
        while (true) {
            System.out.println("Livros alugados atualmente:");
            for (int i = 0; i < alugados.size(); i++) {
                System.out.printf("%2d - %s\n", i + 1, alugados.get(i).toString());
            }
            System.out.println("Escolha o número do livro que vc quer devolver, ou 0 para sair sem devolver nenhum");
            try {
                int opt = Integer.parseInt(this.scanner.nextLine()) - 1;
                if (opt == -1) {
                    return false; // nenhum foi devolvido
                }
                if (opt < 0 || opt >= alugados.size()) {
                    System.out.println("número inválido");
                } else {
                    this.devolucao(alugados, alugados.get(opt));
                    return true; // livro devolvido
                }
            } catch (Exception e) {
                System.out.println("Digite um número válido");
            }
        }
    }

    private boolean simOuNao(String mensagem) {
        while (true) {
            System.out.println(mensagem);
            String opcao = this.scanner.nextLine().toLowerCase();
            switch (opcao) {
                case "s", "sim":
                    return true;
                case "n", "nao", "não":
                    return false;
                default:
                    System.out.println("Digite apenas s/sim/n/nao/não");
            }
        }
    }
}

Aqui eu fiz uma versão bem simplificada da biblioteca, mas basicamente ela possui:

  • Map<Usuario, List<Livro>> registro - registro de usuários e os respectivos livros que cada um alugou
  • Map<Livro, Integer> catalogo - catálogo de livros e a respectiva quantidade disponível de cada um
  • maxLivrosPorUsuario - quantidade máxima de livros que cada usuário pode alugar

A biblioteca também tem uma referência ao Scanner. Para esta versão inicial fiz assim para simplificar o exemplo, mas isso pode ser melhorado para ficar em outra classe que controla as interações com o usuário. Assim deixa a biblioteca somente com a responsabilidade de gerenciar livros (disponibilidade e aluguéis). Por ora, deixei assim mesmo :slight_smile:


Por fim, no main vc cria a biblioteca e faz as interações com o usuário. No código abaixo eu não criei todos os métodos, só coloquei alguns pra te dar a ideia geral.

Arquivo Main.java:

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        // cada usuário pode ter no máximo 3 livros por vez
        Biblioteca biblioteca = new Biblioteca(3, scanner);

        String mensagem = "== Biblioteca ==\n1 - Entrar\n2 - Registrar-se\n3 - Listar Usuarios\n4 - Adiconario Livro\n5 - Listar Livro\n6 - Alugar Livro\n7 - Devolver Livro\n0 - Sair\n";
        while (true) {
            int opcao = lerNumero(scanner, mensagem);
            switch (opcao) {
                case 2:
                    cadastrarUsuario(biblioteca, scanner);
                    break;

                case 4:
                    adicionarLivro(biblioteca, scanner);
                    break;
                // etc...
            }
        }
    }

    // método auxiliar para ler um número
    static int lerNumero(Scanner scanner, String mensagem) {
        // enquanto não digitar um número, pede para digitar novamente
        while (true) {
            try {
                System.out.print(mensagem);
                return Integer.parseInt(scanner.nextLine());
            } catch (Exception e) {
                System.out.println("Digite um número válido");
            }
        }
    }

    static void cadastrarUsuario(Biblioteca biblioteca, Scanner scanner) {
        System.out.print("Digite seu nome: ");
        String nome = scanner.nextLine();
        System.out.print("Digite seu CPF: ");
        String cpf = scanner.nextLine();

        biblioteca.registrar(new Usuario(nome, cpf));
    }

    private static void adicionarLivro(Biblioteca biblioteca, Scanner scanner) {
        System.out.print("Digite o Titulo do livro: ");
        String titulo = scanner.nextLine();
        System.out.print("Digite o Autor do livro: ");
        String autor = scanner.nextLine();
        System.out.print("Digite o ISBN do livro: ");
        String isbn = scanner.nextLine();
        int ano = lerNumero(scanner, "Digite o ano de publicação do livro: ");

        biblioteca.adicionarLivro(new Livro(titulo, autor, isbn, ano));
    }
}

Acho que assim as responsabilidades ficam bem separadas, em vez de ter coisas como o Usuario recebendo um Scanner no construtor, e ele mesmo fazendo a leitura dos dados. A meu ver, ler os dados é uma tarefa separada, e o construtor apenas recebe as informações e cria um usuário. Já os dados, podem vir de qualquer lugar (do Scanner, de um arquivo, de uma chamada HTTP para uma API, do banco de dados, etc), e não é responsabilidade da classe Usuario saber desses detalhes.

Separando as responsabilidades (uma classe lê os dados, outra usa esses dados para criar uma instância, etc) fica bem mais organizado, facilitando a manutenção e evolução do código.