Sei que o tópico já foi resolvido, mas eu particularmente não gosto dessa ideia de aceitar algo que “funciona, mas não sei porquê”. É importante entender o que acontece com seu código, senão você vai passar a vida “programando por coincidência”.
O que acontece é que ao fechar um Scanner
, o stream que ele usa também é fechado. Como regra geral, é importante fechar todo recurso que abrimos (arquivos, conexões de rede, de banco de dados, etc). Mas o System.in
é exceção, pois ele é um recurso “especial”, gerenciado pela JVM, e uma vez fechado, você não consegue reabri-lo.
E é aí que está o problema, seu código está fechando o System.in
e depois tentando usá-lo novamente. Por exemplo:
Vamos supor que primeiro digitei 0
. Então tamanhoTabela
será zero, o Scanner
é fechado (e consequentemente, o System.in
também), mas como tamanhoTabela
é menor que 1, o do
/while
continua executando.
Então na próxima iteração ele tentará ler novamente do System.in
, mas como ele está fechado, será lançada uma exceção. Então o código cai em dos catch
e imprime a mensagem de erro. Como não foi possível ler do System.in
, o valor de tamanhoTabela
continua inalterado (ou seja, continua sendo zero), e por isso o loop continua (tenta ler novamente do System.in
, que está fechado, lança exceção, etc).
Por isso que “funciona” se não fechar o Scanner
, pois aí o System.in
não estará fechado e será possível ler outro valor.
Mas além disso, será que você precisa criar um novo Scanner
a cada iteração? Por que não criar um apenas no início? Além disso, como a entrada está sendo via teclado, é melhor usar nextLine
, pois usar nextInt
esconde algumas armadilhas (leia aqui para saber mais).
Então eu sugiro fazer assim:
// cria o Scanner apenas uma vez, fora do loop
Scanner scanner = new Scanner(System.in);
int tamanhoTabela;
while (true) {
try {
System.out.print("\nDigite quantas linhas você quer sua tabela?\nDigite um número inteiro e positivo: ");
tamanhoTabela = Integer.parseInt(scanner.nextLine());
if (tamanhoTabela < 1) {
System.out.println("O número deve ser positivo");
} else {
break; // interrompe o while
}
} catch (NumberFormatException e) {
System.out.print("\nVocê não digitou um número");
}
}
System.out.println("\nLinhas = " + tamanhoTabela);
Ou seja, enquanto não for digitado um número válido, o loop continua. Se o número for válido, use break
para interromper o loop.
Algumas pessoas “não gostam” de break
e preferem fazer algo assim:
Scanner scanner = new Scanner(System.in);
int tamanhoTabela = -1;
while (tamanhoTabela < 1) {
try {
System.out.print("\nDigite quantas linhas você quer sua tabela?\nDigite um número inteiro e positivo: ");
tamanhoTabela = Integer.parseInt(scanner.nextLine());
if (tamanhoTabela < 1) {
System.out.println("O número deve ser positivo");
}
} catch (NumberFormatException e) {
System.out.print("\nVocê não digitou um número");
}
}
System.out.println("\nLinhas = " + tamanhoTabela);