Выбрасывается исключение java.util.NoSuchElementException при закрытии Scanner
Итак. Строилась программа по создании базы студентов. Есть класс Студент(Student.java):
import java.util.Scanner;
public class Student {
private String firstName;
private String lastname;
private int gradeLevel;
private int balance;
private String followingCourse;
private String ID;
private String[] courses;
public Student() {
System.out.println();
Scanner sc = new Scanner(System.in);
System.out.print("Enter the name: ");
firstName = sc.nextLine();
System.out.print("Enter the last name: ");
lastname = sc.nextLine();
System.out.print("Enter grade level: ");
gradeLevel = sc.nextInt(); // Сделать проверку на введеное число
sc.nextLine();
System.out.print("Enter balance: ");
balance = sc.nextInt();
sc.nextLine();
// Сгенерировать ID
//sc.close();
}
public void showInfo() {
System.out.println();
System.out.print("First name: " + firstName + " \\ ");
System.out.println("Last name: " + lastname);
System.out.println("Grade Level: " + gradeLevel);
System.out.println("ID: " + ID);
System.out.println("Balance: " + balance);
System.out.println("followng courses: ");
System.out.println();
}
}
Есть класс Базы(DataBase.java):
import java.util.Scanner;
public class DataBase {
private Student[] StudentBase; // Общая база всех студентов
private int studentCount = 0; // Количество студентов
private Student[] History;
private Student[] Math;
private Student[] English;
private Student[] Chemistry;
private Student[] CompScience;
public DataBase() { StudentBase = new Student[0]; } // создание базы данных
/* Добавить студентов в базу */
public void AddStudents() {
Scanner scan = new Scanner(System.in);
System.out.print("How many students should be added: ");
int num = scan.nextInt();
if(StudentBase.length == 0) {
StudentBase = new Student[num];
}else {
// Перепись базы
Student[] temp = new Student[studentCount+num];
for(int i = 0; i < StudentBase.length; i++)
temp[i] = StudentBase[i];
StudentBase = temp;
}
// Добавление студентов // Проблема добавления студентов
for(int i = studentCount; i <studentCount + num; i++) {
StudentBase[i] = new Student();
}
studentCount += num; // Прибавим количество студентов в конце
scan.close();
}
/* Методы для показа информации */
public void showInfo() {
for(int i = 0; i < StudentBase.length; i++) {
StudentBase[i].showInfo();
}
}
/* Добавить массивы разынх курсов */
/* Метод для поступления на курс */
}
И происходит выполнение программы:
public class DatabaseApp {
public static void main(String[] args) {
DataBase dataBase = new DataBase();
dataBase.AddStudents();
dataBase.showInfo();
dataBase.AddStudents();
}
}
При добавлении студентов dataBase.AddStudents(); в методе класса DataBase открывается сканер Scanner scan = new Scanner(System.in), после чего, он закрывается: scan.close();. И когда вызывается повторно метод AddStudents(): dataBase.AddStudents(); выбрасывается исключение java.util.NoSuchElementException. Причем, если убрать строчку scan.close(); в классе DataBase, исключение не выбрасывается.
Как это связано с закрытием Scanner, и как исправить эту ошибку?
Ответы (1 шт):
Проблема в том, что метод Scanner.close закрывает тот InputStream, который ему передали.
Это значит, что после первого вызова AddStudents вы закрываете System.in, а значит последующие попытки чтения из него приведут к ошибке, что, собственно, и просходит.
В этом случае правильно (и проще всего тоже) не закрывать scanner, так как у вас всегда передается System.in, а этот поток вообще закрывать не имеет смысла.
В некоторых случаях у вас может быть универсальный код со Scanner, то есть такой, который не знает какой именно ему InputStream передается, но он принимает его во владение. Под владением я имею ввиду то, что этот код является ответственным за закрытие переданного InputStream. И так как он не знает, передан ему поток ввода созданный из файла (который можно и должно закрывать) или System.in, то тут возникает проблема.
Ее решают тем, что передают не непосредственно System.in, а заворачивают его в декоратор для InputStream, который игнорирует вызов метода close. В JDK такого нету (по крайней мере до версии 8 точно не было, может сейчас изменилось что-то), но есть в apache commons.