TL; DR Use scanner.skip("\\R")
antes de cada scanner.newLine()
chamada, que é executada após:
scanner.next()
scanner.next*TYPE*()
método.
Coisas que você precisa saber:
O texto que representa poucas linhas também contém caracteres imprimíveis entre as linhas (nós os chamamos de separadores de linha), como
- retorno de carro (CR - em literais String representados como
"\r"
)
- avanço de linha (LF - em literais String representados como
"\n"
)
quando você está lendo dados do console, ele permite que o usuário digite sua resposta e, quando terminar, ele precisa de alguma forma confirmar esse fato. Para isso, o usuário deve pressionar a tecla "Enter" / "Return" no teclado.
O importante é que essa chave, além de garantir a colocação dos dados do usuário na entrada padrão (representada pela System.in
qual é lida porScanner
), também envie separadores de linha dependentes do SO (como no Windows \r\n
) depois dela.
Portanto, quando você pede ao usuário um valor como age
, e o usuário digita 42 e pressiona enter, a entrada padrão conterá"42\r\n"
.
Problema
Scanner#nextInt
(e outros métodos) não permite que o Scanner consuma esses separadores de linha. Ele as lerá (de que outra forma o Scanner saberia que não há mais dígitos do usuário que representam valor do que espaços em branco?) Que os removerão da entrada padrão, mas também armazenarão em cache esses separadores de linha internamenteScanner#nextType
System.in
age
. O que precisamos lembrar é que todos os métodos do Scanner estão sempre digitalizando a partir do texto em cache.
Agora, Scanner#nextLine()
basta coletar e retornar todos os caracteres até encontrar os separadores de linha (ou final do fluxo). Porém, como os separadores de linha após a leitura do número no console são encontrados imediatamente no cache do Scanner, ele retorna String vazia, o que significa que o Scanner não conseguiu encontrar nenhum caractere antes desses separadores de linha (ou no final do fluxo).
BTW nextLine
também consome esses separadores de linha.
Solução
Portanto, quando você deseja solicitar o número e a linha inteira, evitando a sequência vazia como resultado de nextLine
,
- separador de linha de consumo deixado por
nextInt
cache Scanners
- chamando
nextLine
,
- ou o modo mais legível da IMO seria ligando
skip("\\R")
ou skip("\r\n|\r|\n")
permitindo que o Scanner pule parte correspondente ao separador de linhas (mais informações sobre \R
: https://stackoverflow.com/a/31060125 )
- não use
nextInt
(nem next
, nem nenhum nextTYPE
método). Em vez disso, leia os dados inteiros linha por linha usando nextLine
e analisando números de cada linha (assumindo que uma linha contenha apenas um número) para o tipo apropriado, como int
via Integer.parseInt
.
BTW : os métodos podem ignorar delimitadores (por padrão, todos os espaços em branco, como guias, separadores de linha), incluindo os armazenados em cache pelo scanner, até encontrar o próximo valor não-delimitador (token). Graças a isso para entrada como códigoScanner#nextType
"42\r\n\r\n321\r\n\r\n\r\nfoobar"
int num1 = sc.nextInt();
int num2 = sc.nextInt();
String name = sc.next();
será capaz de atribuir corretamente num1=42
num2=321
name=foobar
.