Error using scanner.close()

I'm trying to run this code in Java, using Eclipse. The same performs once normal. When trying to repeat the operation (choosing option 1) gives error as picture below.

If I remove the scanner.close(); it works normal, running multiple times.

I have already found something about it on the internet, including here, but I did not understand and could not solve the problem.

Could anyone help by clarifying why gives the error and how to solve the mistake?

import java.util.Scanner;

public class Exercicio{

    public int menu() {
        Scanner scanner = new Scanner(System.in);
        int opcao;
            System.out.println("ESCOLHA UMA OPÇÃO:");
            System.out.print("1-Imprime opção escolhida\n0-Sair\nOpção:");
            opcao = scanner.nextInt();
        scanner.close(); //ERRO AQUI. SE REMOVER ESTA LINHA, FUNCIONA.
        return opcao;
    }

    public static void main (String[] args) {

        int opcao;
        Exercicio exercicio = new Exercicio();

        do {
            opcao = exercicio.menu();

            switch (opcao) {                

                case 0 : 
                break;

                case 1 : 
                    System.out.println("Você escolheu a opção 1.\n");
                break;

            }
        }while (opcao != 0);
    }
}

image

Author: hkotsubo, 2019-05-02

1 answers

This happens because by closing the Scanner, you also close the object it encapsulates. In case, you end up closing the System.in.

Only System.in is a "special" feature, managed by the JVM, and once closed, it cannot be reopened.

So what happens is:

  • you call the method menu, which creates the Scanner, reads the option and closes the Scanner (and consequently, closes the System.in).
  • the second time you call the method menu (since it is within a loop), you re-create the Scanner, passing the System.in (which is now closed)
  • when trying to read the data, it gives error because System.in is closed

The solution is not to close the System.in inside the loop. You could create the Scanner out of the loop and pass it to the menu method, for example. And using a block try-with-resources, you don't even need to call close(), as this is automatically called at the end:

// agora recebe o Scanner, em vez de criar toda hora
public int menu(Scanner scanner) {
    int opcao;
    System.out.println("ESCOLHA UMA OPÇÃO:");
    System.out.print("1-Imprime opção escolhida\n0-Sair\nOpção:");
    opcao = scanner.nextInt();
    return opcao;
}

// dentro do main
int opcao;
Exercicio exercicio = new Exercicio();
try (Scanner scanner = new Scanner(System.in)) {
    do {
        opcao = exercicio.menu(scanner);
        switch (opcao) {
            case 0:
                break;
            case 1:
                System.out.println("Você escolheu a opção 1.\n");
                break;
        }
    } while (opcao != 0);
} catch (Exception e) {
    // tratar os erros
}

About the fact that you need to close System.in or not, I talk in more detail here .


The try-with-resources syntax is available from Java 7. For earlier versions, just do:

int opcao;
Scanner scanner = null;
try {
    scanner = new Scanner(System.in);
    do {
        opcao = menu(scanner);
        switch (opcao) {
            case 0:
                break;
            case 1:
                System.out.println("Você escolheu a opção 1.\n");
                break;
        }
    } while (opcao != 0);
} catch (Exception e) {
    // tratar os erros
} finally {
    if (scanner != null) {
        scanner.close();
    }
}
 3
Author: hkotsubo, 2019-05-02 01:07:42