Problema com leitura de teclado usando Scanner

Pessoal, estou aprendendo Java agora, e no código abaixo estou usando a biblioteca Scanner para dar entrada nas variáveis através do teclado, porém, quando chega na hora de atribuir valor a variável Rua da Classe Endereco, dá erro como se tivesse armazenado um Buffer. Portanto, criei uma nova variável para armazenar os dados (Scanner dados2 = new Scanner(System.in) e a partir da Classe Endereco passei a usar e deu certo, alguém sabe me explicar por que no código abaixo começa a dar erro a partir da Classe Endereco?

package Programa;

public class Endereco {
String rua;
String bairro;
String Cidade;
String Estado;
String Pais;
int numero;
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub

}

}

package Programa;

public class Nascimento {
int dia;
int mes;
double ano;
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub

}

}

package Programa;

public class Nome {
String nome;
String sobrenome;
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub

}

}
package Programa;

import java.util.Scanner;

public class Principal {
Nome nome = new Nome();
Nascimento nascimento = new Nascimento();
Endereco endereco = new Endereco();

/**
 * @param args
 */
public static void main(String[] args) {
	// TODO Auto-generated method stub
	

	}

}
package Programa;

import java.util.Scanner;

public class Programa {

/**
 * @param args
 */
public static void main(String[] args) {
	// TODO Auto-generated method stub
	Principal Cliente = new Principal();
	Scanner dados = new Scanner(System.in); 
	Scanner dados2 = new Scanner(System.in);
	
	
	System.out.println("Informe o nome do cliente: ");
	Cliente.nome.nome = dados.nextLine();
	System.out.println("Informe o sobrenome: ");
	Cliente.nome.sobrenome = dados.nextLine();
	System.out.println("Informe o dia de Nascimento");
	Cliente.nascimento.dia = dados.nextInt();
	System.out.println("Informe o mes de Nascimento");
	Cliente.nascimento.mes = dados.nextInt();
	System.out.println("Informe o ano de Nascimento");
	Cliente.nascimento.ano = dados.nextDouble();
	System.out.println("Informe o Endereço");
	System.out.println("Rua: ");
	Cliente.endereco.rua = dados.nextLine();
	System.out.println("Número: ");
	Cliente.endereco.numero = dados.nextInt();
	System.out.println("Bairro: ");
	Cliente.endereco.bairro = dados.nextLine();
	System.out.println("Cidade: ");
	Cliente.endereco.Cidade = dados.nextLine();
	System.out.println("Estado: ");
	Cliente.endereco.Estado = dados.nextLine();
	System.out.println("País: ");
	Cliente.endereco.Pais = dados.nextLine();
	
	
}

}

Pessoal,

Já descobri o erro:
O problema está no método nextLine depois do nextInt. Se leres a documentação do método nextLine, ficas a saber que o método avança para a próxima linha e devolve a linha “comida”, isto é, o método vai avançando, caracter a caracter, até encontrar um caracter de mudança de linha quando o encontra, coloca um ponteiro para a posição seguinte ao delimitador, que é a linha a seguir, e devolve todo o texto que processou até chegar ao delimitador.
O nextInt não faz isso, na verdade o nextInt não consome o delimitador, ele vai ler um conjunto de caracteres que representem um inteiro, e caso tenha sucesso, devolve esse inteiro mas deixa o delimitador na stream e não muda de linha.

Resultado, se analisarmos o comportamento de teu código vemos que:

?o primeiro nextLine obtém uma linha e consome o ‘\n’
?o nextInt obtém um inteiro e não consome o ‘\n’
?o segundo nextLine vai ler tudo até ao ‘\n’, que já se encontra no buffer porque o nextInt não o removeu, resultado, o método encontra o caracter que estava à procura e não precisa de mais nada, devolver “”, uma vez que só existia o delimitador, para o Scanner, isso é uma string vazia

A forma simples de resolver o problema será invocar o método nextLine logo após à invocação do nextInt, o que vai resultar no consumo dos dados que se encontram a mais dentro do buffer.

O problema que estás a ter é de que existem dados dentro do buffer que não foram lidos pelo nextInt, ao invocares o nextLine esses dados vão ser lidos, esta é uma das razões pelas quais não gosto de usar Scanner para ler dados do teclado, não é simples trabalhar com o buffer interno, para, por exemplo, remover dados que não interessam, ou limpar o buffer.

Alguém conhece alguma outra forma de dar entrada através do teclado que seja mais eficiente?

1 curtida