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);