Reputation: 312
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
Reputation: 272760
In your addBookToLibrary
method, you close
the Scanner
s 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