Captura de dados antes de Captura de linha: "erro" e solução, em Java.
Tags: java, backend, data
Published: 2023-08-31 14:53:07

Quando estamos utilizando a classe Scanner para leitura de dados, nos deparamos com uma situação que não é tão fácil compreender para quem está iniciando na linguagem de programação Java. Acontece que: quando é utilizado um método de captura de dados (_next(), nextInt(), nextFloat(), nextDouble(), nextShort(), nextLong(), nextBoolean(), nextChar(), nextBigdecimal(), nextBigInteger()_) e depois é utilizado o método de captura de uma linha (_nextLine()_), este último vai capturar a quebra de linha (\n) do método de captura de dados anteriormente utilizado, e não vai permitir a captura da linha do usuário. Calma que vou exemplificar:

```
import java.util.Scanner;
public class ExemploScanner{
    public static void main(String[] args){
        //Criando as variáveis para captura dos dados, e armazenamento desses dados
        Scanner input = new Scanner(System.in);
        int number;
        String line;
        //Recebendo o número digitado pelo usuário
        number = input.nextInt();
        //Recebendo a linha (uma frase por exemplo) digitada pelo usuário
        line = input.nextLine();
        //Imprimindo as informações capturadas
        System.out.println(“numero: ” + number + “ frase: ” + line);
    }
}
```
No exemplo acima vamos ler um inteiro e depois ler uma linha completa, após inserir o número (por exemplo o número 10) o programa já encerra e imprime:

numero: 10 frase:

Nossa variável “number” foi alimentada, entretanto nossa variável “line” não (será que não foi mesmo?). Porque?

Bom, acontece que (como diz a própria documentação oficial da classe Scanner) o método _nextLine()_ vai retornar “a linha que foi pulada”, ou seja, o conteúdo da linha anterior antes da gente pulá-la (em outras palavras: Pressionar o ENTER). Mas, se o usuário não digitou nada na linha, como que ele encerrou (deduzindo que algo foi inserido)? Aí entra em jogo o nosso método anterior utilizado (no nosso exemplo: _nextInt()_). Esse método vai capturar apenas o inteiro, e não a linha completa. Percebam que existe uma linha, e depois que o inteiro for consumido, continua existindo uma linha (que é pulada depois que o usuário inserir o inteiro e pressionar Enter). Então, essa linha que foi pulada é que vai ser atribuída para o _nextLine()_ depois que o usuário apertar Enter. Ou seja, ele consumiu uma linha que está em branco.

O mesmo vale caso a gente utilize qualquer método “nextAlgumTipoDeDadoEspecífico” antes de um _nextLine()_. Vamos utilizar no exemplo abaixo o método _next()_ para capturar uma palavra:

```
import java.util.Scanner;

public class ExemploScanner{

    public static void main(String[] args){

        //Criando as variáveis para captura dos dados, e armazenamento desses dados

        Scanner input = new Scanner(System.in);

        String word;

        String line;

        //Recebendo uma palavra do usuário

        word =input.next();

        //Recebendo a linha (uma frase por exemplo) digitada pelo usuário

        line = input.nextLine();

        //Imprimindo as informações capturadas

        System.out.println(“palavra: ” + word  + “ frase: ” + line);

    }

}
```

Após inserir a palavra (vamos supor que digitamos “Java”), da mesma forma que com o número, o programa encerra e já mostra:

palavra: Java frase:

Mas isso ocorre apenas se utilizarmos os métodos Scanner de captura de dados antes de usar o de captura de linha, se você utilizar primeiro a captura de linha e depois a de dados, isso não ocorre, pois a captura de linha vai (adivinhem) capturar a linha toda, e já a captura de dados não, vai capturar apenas o dado específico que corresponde a seu método.

Apenas para confirmar o que foi dito, vamos inverter a ordem de captura dos dados, primeiro vamos capturar a linha depois o número:

```
import java.util.Scanner;

public class ExemploScanner{

    public static void main(String[] args){

        //Criando as variáveis para captura dos dados, e armazenamento desses dados

        Scanner input = new Scanner(System.in);

        int number;

        String line;

        //Recebendo a linha (uma frase por exemplo) digitada pelo usuário

        line = input.nextLine();

        //Recebendo o número digitado pelo usuário

        number = input.nextInt();

        //Imprimindo as informações capturadas

        System.out.println(“numero: ” + number  + “ frase: ” + line);

    }

}
```

Ao executar nosso arquivo vamos digitar “Hello World” na primeira linha, e o número 7 na segunda. Nossa saída será:

numero: 7 frase: Hello World

Percebam que a única alteração que fizemos foi mudar a ordem de captura das variáveis. Sempre que forem utilizados os métodos de captura de dados específicos da classe Scanner, será produzido a quebra de linha. E se for utilizado o _nextLine()_ após ele(s), ocorrerá esse problema. E então, como solucionar?

Você pode pensar que para solucionar basta utilizar dois _nextLine()_’s, um para capturar a quebra de linha e outro para capturar a frase do usuário. De fato vai solucionar, mas não é nem de longe a melhor forma.

Com o passar do tempo como desenvolvedor, você vai perceber que existem as boas práticas que regem as linguagens de programação, e que vai existir algumas diferentes formas (corretas) de solucionar um problema. Vamos utilizar uma dessas formas para esse problema, que vai ser: tratar a entrada dos dados do usuário (receber tudo em String e para os casos de inteiros, vamos convertê-los).

Para fazer isso, vamos utilizar nas entradas o método _nextLine()_ e utilizar o método _Integer.parseInt()_ no caso dos inteiros. E para ficar melhor o exemplo, vamos supor que queremos fazer um cálculo com o número inteiro, multiplicando-o por 10 (para haver uma necessidade de utilização do mesmo como número de fato):

```
import java.util.Scanner;

public class ExemploScanner{

    public static void main(String[] args){

        //Criando as variáveis para captura dos dados, e armazenamento desses dados

        Scanner input = new Scanner(System.in);

        int number;

        String line;

        //Recebendo o número digitado pelo usuário

        number = Integer.parseInt(input.nextLine());

        //Recebendo a linha (uma frase por exemplo) digitada pelo usuário

        line = input.nextLine();

        //Imprimindo as informações capturadas

        System.out.println(“numero: ” + (number * 10)  + “ frase: ” + line);

    }

}
```

Agora foi! Dá pra ficar ainda melhor, tornando o programa mais resistente a entradas inválidas (verificando se o valor inserido é inteiro, se for, faz o cálculo, se não, retorna uma mensagem informando para o usuário inserir um valor válido). Fica de atividade para vocês. ;)

Foi exemplificado com o _nextInt()_ e sua conversão específica, mas a lógica serve para cada tipo de dado e seu método _next_ correspondente. 

Por exemplo, para converter para float utiliza-se _Float.parseFloat()_, para converter para Double: _Double.parseDouble_, para booleano: _Boolean.parseBoolean_…

Espero que tenha ajudado, abraço a todos!