GainzNerd
GainzNerd

Reputation: 312

java.util.NoSuchElementException when reading user input in switch statement

Running into an error with this project I'm working on for a computer science course, and hoping someone can give me insight into what may be happening. A bit of background to what's occurring in the code:

In the below code, I have the start of my program which displays a UI menu and asks for user input and uses a switch statement to run appropriate methods based on user input.

    /**
     * Start of program
     */
    public static void main(String[] args) {

        Library library = new Library();

        char userChoice; //Stores what menu item the user chose
        Scanner userMenuChoiceScanner = new Scanner(System.in);
        boolean loop = true;

        displayMenu(); //Displays main UI menu
        userChoice = Character.toLowerCase(userMenuChoiceScanner.nextLine().charAt(0)); //Gets user's menu choice

        /*Loops UI menu afer user has made menu choice and exits loop if user choses 'q' from menu.*/
        while(loop) {

            /* Switch descides what menu choice user has made and whether to prin menu UI again, load, 
             * search, print, or analyze a music catalog, or to quit program.
             */
            switch(userChoice) {
            case 'm':
                System.out.println();
                displayMenu();
                userChoice = Character.toLowerCase(userMenuChoiceScanner.nextLine().charAt(0));
                break;
            case 'p':
                System.out.println();

                if(library.getBooks().size() != 0) {
                    printLibrary(library);
                } else {
                    System.out.println("There are no books in the library. Please add a book first.");
                }

                System.out.print("Please enter a command (press 'm' for Menu):");
                userChoice = Character.toLowerCase(userMenuChoiceScanner.nextLine().charAt(0));
                break;
            case 'a':
                System.out.println();
                addBookToLibrary(library);
                System.out.print("Please enter a command (press 'm' for Menu):");
                userChoice = Character.toLowerCase(userMenuChoiceScanner.nextLine().charAt(0));
                break;
            case 'd':

                System.out.println();

                if(library.getBooks().size() != 0) {
                    deleteBookFromLibrary(library);
                } else {
                    System.out.println("There are no books in the library. Please add a book first.");
                }

                System.out.print("Please enter a command (press 'm' for Menu):");
                userChoice = Character.toLowerCase(userMenuChoiceScanner.nextLine().charAt(0));
                break;
            case 'r':           
                System.out.println();

                if(library.getBooks().size() != 0) {
                    readBookFromLibrary(library);
                } else {
                    System.out.println("There are no books in the library. Please add a book first.");
                }

                System.out.print("Please enter a command (press 'm' for Menu):");
                userChoice = Character.toLowerCase(userMenuChoiceScanner.nextLine().charAt(0));
                break;
            case 'q':
                System.out.println();
                System.out.println("Thank you! Goodbye!");
                loop = false;
                break;
            default:
                System.out.println();
                System.out.println("Invalid selection!");
                System.out.print("Please enter a command (press 'm' for Menu):");
                userChoice = Character.toLowerCase(userMenuChoiceScanner.nextLine().charAt(0));
                System.out.println();

            }
        }

        userMenuChoiceScanner.close();



    }

What's occuring is when tthe user makes a choice, it goes into the appropriate methods and fulfills it's tasks there, then when it returns to the switch statement to get a new user input, it throws a java.util.NoSuchElementException error as if the scanner stream was closed, but I don't close the scanner until the end (the stream should still be open).

The switch statement is set up in a way where a book must be added (the user must chose 'a' first) before any other option can be chosen. Here is the code to he addBookToLibrary() method which has a couple scanners which are opened and closed. I assume maybe closing out these scanners may be causing the issue?

    /**
     * Adds new book to library
     * @param library ArrayList object which holds book objects
     */
    public static void addBookToLibrary(Library library) {
        Scanner addBookScanner = new Scanner(System.in);
        String title = "";
        String author = "";
        String genre = "";
        String filename = "";
        boolean addStatus = false;


        /*Asks user for book details */
        System.out.println("Enter the details of the book you want to add to the library:");
        System.out.println("What is the book title?");
        title = addBookScanner.nextLine();
        System.out.println("What is the author's name?");
        author = addBookScanner.nextLine();
        System.out.println("What is book genre?");
        genre = addBookScanner.nextLine();
        System.out.println("What is the book's filename?");
        filename = addBookScanner.nextLine();
        addBookScanner.close();

        Book newBook = new Book(author, title); //creates new book with author and title set

        newBook.setGenre(genre); //sets book genre

        File bookFile = new File(System.getProperty("user.dir") + '\\' + filename); //used to check if file user provided exists
        System.out.println(bookFile);
        /*Checks to see if file user provided actually exists*/
        if(bookFile.exists()) {

            try {

                newBook.setFilename(filename);

            }catch(Exception e) {

            }

        }
        else {

            Scanner getNewFilenameScanner = new Scanner(System.in);

            //Continues to ask user for new filename if file doesn't exist
            do {
            System.out.println("I'm sorry, but the file you specified does not exist.");
            System.out.print("Enter a new file name:");
            bookFile = new File(getNewFilenameScanner.nextLine());

            }while (!(bookFile.exists()));

            getNewFilenameScanner.close();
        }

        addStatus = library.addBook(newBook); //adds book to library

        if(addStatus) {
            System.out.println("Book was successfully added!");
        }
        else {
            System.out.println("Book was not successfully added. Please try again.");
        }
    }

This code worked perfectly in a previous project, so I'm not certain why it's not working now. Any help would be greatly appreciated.

Thank you so much

Upvotes: 0

Views: 259

Answers (1)

Sweeper
Sweeper

Reputation: 272760

In your addBookToLibrary method, you close the Scanners after you are done using them. However, those scanners are connected to System.in, the standard input stream. Closing those scanners will also close the standard input stream, according to the documentation.

What else is connected to the standard input stream? userMenuChoiceScanner! After the standard input stream is closed, userMenuChoiceScanner can't read from it, hence throwing an exception.

Note that although userMenuChoiceScanner is not closed until the very end, the stream that it is reading from is closed.

In fact, you don't need to create multiple scanners here. You only need to use one scanner, and pass it around to different methods. For example, addBookToLibrary could accept a Scanner:

public static void addBookToLibrary(Library library, Scanner s) {

And it will only use s to read inputs. You can pass your userMenuChoiceScanner to it:

addBookToLibrary(library, userMenuChoiceScanner);

As a general rule, you should not close anything that is not opened by you. You didn't open the standard input stream (the JVM did), so you shouldn't close it.

Upvotes: 1

Related Questions