Ir ao conteúdo
  • Cadastre-se
Mike Santos

Java Código com pequeno Bug

Recommended Posts

Na minha lista de exercícios na faculdade, tem uma questão me mostrando um bug que não consigo consertar.

A questão é apenas para coletar o nome de 15 clientes, e o total gasto em certa loja no último ano.

Dependendo do valor, terá um pequeno bônus, enfim, nada complexo.

Eu tentei primeira usando um for, aí apresentou esse bug, depois tentei com while e apresentou esse bug.

O bug é que, na primeira "ida" do laço de repetição, ele funciona normalmente, ele imprime pedindo o nome do cliente, depois imprime pedindo o valor gasto e então ele faz o cálculo e exibe ele.

Porém na segunda volta do laço, ele imprime o "Insira o nome do cliente", mas não deixa preencher, ele já imprime direto o "Insira o valor gasto".

Se alguém puder me ajudar, agradeço.

Segue o código que estou usando e que apresenta o bug:

 

 

    public static void main(String[] args) {

        String nome;
        double val, bonus;
        int i = 0;
        Scanner x = new Scanner(System.in);
        
        while (i < 15) {

            System.out.println("Digite o nome do cliente.");

            nome = x.nextLine();

            System.out.println("Valor das compras no ano passado.");

            val = x.nextDouble();

            if (val <= 1000) {

                bonus = val * 0.10;

            } else {

                bonus = val * 0.15;

            }
            System.out.println("\n... processando ...\n");
            System.out.printf("\nO valor do seu bônus será de: %2.2f\n",bonus);
            i++;
        }
    }

}
 

Compartilhar este post


Link para o post
Compartilhar em outros sites

@Mike Santos Olá. Olha amigo. Isso é sujeira no buffer. A maneira mais recomendada para resolver essa questão pode não parecer a melhor a princípio, mas é a mais eficaz. Teria q fazer uso de um método próprio para ler Strings. O ideal mesmo seria também ter um método para ler um valor do tipo double

Mas com esse método para ler Strings ao q parece já resolveu o problema

Obs: Isso é bastante comum no C, que é a linguagem em q estou focado. Inclusive a gente faz muito funções próprias para ler uma String por exemplo, para limpar o stdin (entenda limpar a sujeira no buffer) e vários outros recursos para lidar com esse problema

Seu código poderia ficaria assim fazendo uso desse método:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner;

public class Aplicacao {

    public static void main(String[] args) {

        String nome;
        double val, bonus;
        int i = 0;
        Scanner x = new Scanner(System.in);

        while (i < 15) {

            System.out.println("Digite o nome do cliente.");
            nome = readString();

            System.out.println("Valor das compras no ano passado.");
            val = x.nextDouble();

            if (val <= 1000) {
                bonus = val * 0.10;
            } else {
                bonus = val * 0.15;
            }
            System.out.println("\n... processando ...\n");
            System.out.printf("\nO valor do seu bônus será de: %2.2f\n",bonus);
            i++;
        }

    }

    public static String readString() {
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
            return reader.readLine();
        } catch (IOException e) {
            throw new RuntimeException("Erro ao ler o dado do teclado");
        }
    }

}

Uma coisa posso te garantir. Cedo ou tarde você vai entender melhor dos problemas referentes a não usar maneiras adequadas para ler um valor do teclado e vai passar a criar seus próprios métodos para ler cada tipo de dado, como Strings, char, int, double, etc... Principalmente quando você trabalhar com projetos maiores. 

Talvez essa não seja a resposta q você gostaria de encontrar, mas vejo q é bom você saber, desde já, dessa questão q mencionei e que está gerando esse bug no seu código.

Se ainda não resolver, vai ser preciso criar um método para fazer a leitura dos valores double da maneira adequada também

Espero q ajude! :thumbsup:

adicionado 3 minutos depois

Esse seria um método ótimo para fazer a leitura de um valor do tipo double:

public static double readDouble() {
    String str = readString();
    try {
        return Double.parseDouble(str);
    } catch(NumberFormatException e) {
        throw new RuntimeException(str + " nao é um double válido");
    }
}

Se porventura interessar posso te passar uma classe toda própria p ser usada para leitura de valores do tipo double, int, Strings, etc... q você já poderia passar a usar em seus projetos

Se interessar é só avisar, ok?

Editado por giu_d

Compartilhar este post


Link para o post
Compartilhar em outros sites

Acredito que sempre que você usa o método nextLine antes da leitura de um número em um laço, o Enter que é dado para entrar com o número acaba caindo no nextLine da iteração seguinte.

 

Uma solução que é simples é você colocar um x.nextLine() após usar o x.nextDouble(), pois ele acaba coletando os caracteres indesejados. Vale lembrar que não precisa armazenar o valor coletado, é só fazer o seguinte:

//...
val = x.nextDouble();
x.nextLine();
//...

 

  • Curtir 1

Compartilhar este post


Link para o post
Compartilhar em outros sites

@iHollyZinhO Exato. Essa seria uma outra alternativa para resolver o problema. Té onde sei você programa em C e sabe bem a respeito desse problema de sujeira no buffer e da importância de limpar o stdin:)

  • Curtir 1

Compartilhar este post


Link para o post
Compartilhar em outros sites

@Mike Santos Olá. Gostei do seu interesse e claro q vou passar os métodos.

Uma das grandes vantagens da programação orientada a objetos é o reaproveitamento de código. Logo, se uma pessoa já se dispôs a criar uma classe para fazer a leitura do console de maneira adequada, essa classe pode ser usada perfeitamente em meus projetos (faço isso com muita frequência) e pode ser usada nos seus projetos ou para quem mais interessar.

Perceba q na classe os métodos são estáticos (static), logo, não é preciso criar um novo objeto da classe ConsoleUtils.

Vou mostrar o exemplo do uso e vai entender melhor essa parte

Segue o código da classe ConsoleUtils:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * Classe utilitária para ler dados do console
 */
public class ConsoleUtils {

    /**
     * Lê uma string do console
     *
     * @return String lida
     */
    public static String readString() {
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
            return reader.readLine();
        } catch (IOException e) {
            throw new RuntimeException("Erro ao ler o dado do teclado");
        }
    }

    /**
     * Lê um valor do tipo int do console
     *
     * @return valor int lido
     */
    public static int readInt() {
        String str = readString();

        try {
            return Integer.parseInt(str);
        } catch (NumberFormatException e) {
            throw new RuntimeException(str + " nao é um int válido");
        }
    }

    /**
     * Lê um valor do tipo double do console
     *
     * @return valor double lido
     */
    public static double readDouble() {
        String str = readString();

        try {
            return Double.parseDouble(str);
        } catch (NumberFormatException e) {
            throw new RuntimeException(str + " nao é um double válido");
        }
    }

    /**
     * Lê uma letra do console
     *
     * @return Letra lida
     * @throws RuntimeException Pode ser lançada em três casos: se nada for
     *                          digitado, se mais de uma letra for digitada e se o
     *                          caractere digitado ou se não for digitada uma letra
     *                          de A a Z
     */
    public static char lerLetra() {

        BufferedReader reader = null;

        try {
            reader = new BufferedReader(new InputStreamReader(System.in));

            // Lê a linha do teclado
            String linha = reader.readLine();

            // A linha não pode ser vazia
            if (linha.trim().isEmpty()) {
                throw new RuntimeException("Nenhuma letra foi digitada");
            }

            // A linha não pode conter mais de um caractere
            if (linha.length() > 1) {
                throw new RuntimeException("Apenas uma letra deve ser digitada");
            }

            // Extrai o caractere digitado
            char letra = linha.charAt(0);

            // O caractere deve ser uma letra
            if (!Character.isLetter(letra)) {
                throw new RuntimeException("Apenas letras devem ser digitadas");
            }

            return letra;

        } catch (IOException e) {
            throw new RuntimeException("Problema ao ler caractere do teclado", e);
        }
    }

}

Segue um a maneira de usar os métodos dessa classe:


public class Leituras {

    public static void main(String[] args) {

        String texto;
        int i;
        double d;
        char c;

        System.out.print("Digite uma string: ");
        texto = ConsoleUtils.readString(); // como os métodos da classe ConsoleUtils são estáticos, basta chamá-los dessa forma

        System.out.print("Digite um numero inteiro: ");
        i = ConsoleUtils.readInt();

        System.out.print("Digite um valor double: ");
        d = ConsoleUtils.readDouble();

        System.out.print("Digite um caractere: ");
        c = ConsoleUtils.lerLetra();

        System.out.println();

        System.out.println("String: " + texto);
        System.out.println("Número inteiro: " + i);
        System.out.println("Número double: " + d);
        System.out.println("Caractere: " + c);

    }

}

Se quiser deixar o método para ler um caractere mais simples, poderia ficar assim:

public static char lerLetra() {

    BufferedReader reader = null;

    try {
        reader = new BufferedReader(new InputStreamReader(System.in));

        // Lê a linha do teclado
        String linha = reader.readLine();

        return linha.charAt(0);

    } catch (IOException e) {
        throw new RuntimeException("Problema ao ler caractere do teclado", e);
    }
}

Obs: Talvez agora você ainda não entenda exatamente a importância de métodos próprios para ler um tipo de dado do teclado, mas pode ter certeza q quando estiver trabalhando em projetos mais complexos, aí sim você vai preferir fazer uso de uma classe como essa, ConsoleUtils, em seus projetos ou mesmo tirar um tempo para você mesmo criar seus métodos para ler um int, um double, um char, etc...

Mas percebi q você já pôde ver a importância de métodos como esses. É isso aí!

Qualquer dúvida é só perguntar, ok?

Editado por giu_d
corrigir comentário

Compartilhar este post


Link para o post
Compartilhar em outros sites

@giu_d muito obrigado.

Estou na faculdade fazendo Programação II, e a linguagem ensinada é o Java, ainda não entendo muito bem disso tudo, mas pretendo aprender bem e me profissionalizar.

E estou achando interessante esse paradigma orientado a objeto, antes tinha tido algum pouco contato com algumas linguagens imperativas, mas orientada a objeto é a primeira vez.

  • Obrigado 1

Compartilhar este post


Link para o post
Compartilhar em outros sites

@Mike Santos Olá. Já era para ter te falado isso antes, mas creio q ainda dá tempo

Eu aprendi os principais conceitos sobre orientação a objetos com o Java também e posso dizer que vale muito a pena!

Essa é a tendência nos dias de hoje, programação orientada a objetos!

Não que inda não tenha espaço no mercado de trabalho para programação procedural (estruturada)

Apenas estou te contando a respeito do minha ligação com o Java e programação orientada a objetos para te encorajar um pouco mais a ir a fundo nesse assunto. É algo que se você aprender de maneira adequada vai usar para a vida toda!

Vá fundo com seus estudos sobre orientação a objetos e garanto que não vai se arrepender

Dica importante: A boa notícia que tenho p te dar é que com o passar do tempo as coisas vão "clareando" cada vez mais. Lembre sempre disso, ok?

Compartilhar este post


Link para o post
Compartilhar em outros sites

Crie uma conta ou entre para comentar

Você precisar ser um membro para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar agora





Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas publicações sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×