Java.util.NoSuchElementException - считывание пользователем сканера
Я новичок в использовании Java, но у меня есть предыдущий опыт работы с С#. Проблема, с которой я столкнулась, связана с чтением пользовательского ввода с консоли.
Я запускаю ошибку "java.util.NoSuchElementException" с этой частью кода:
payment = sc.next(); // PromptCustomerPayment function
У меня есть две функции, которые получают пользовательский ввод:
- PromptCustomerQty
- PromptCustomerPayment
Если я не вызываю PromptCustomerQty, тогда я не получу эту ошибку, что заставляет меня поверить, что я делаю что-то не так со сканером. Ниже приведен пример моего полного кода. Я ценю любую помощь.
public static void main (String[] args) {
// Create a customer
// Future proofing the possabiltiies of multiple customers
Customer customer = new Customer("Will");
// Create object for each Product
// (Name,Code,Description,Price)
// Initalize Qty at 0
Product Computer = new Product("Computer","PC1003","Basic Computer",399.99);
Product Monitor = new Product("Monitor","MN1003","LCD Monitor",99.99);
Product Printer = new Product("Printer","PR1003x","Inkjet Printer",54.23);
// Define internal variables
// ## DONT CHANGE
ArrayList<Product> ProductList = new ArrayList<Product>(); // List to store Products
String formatString = "%-15s %-10s %-20s %-10s %-10s %n"; // Default format for output
// Add objects to list
ProductList.add(Computer);
ProductList.add(Monitor);
ProductList.add(Printer);
// Ask users for quantities
PromptCustomerQty(customer, ProductList);
// Ask user for payment method
PromptCustomerPayment(customer);
// Create the header
PrintHeader(customer, formatString);
// Create Body
PrintBody(ProductList, formatString);
}
public static void PromptCustomerQty(Customer customer, ArrayList<Product> ProductList) {
// Initiate a Scanner
Scanner scan = new Scanner(System.in);
// **** VARIABLES ****
int qty = 0;
// Greet Customer
System.out.println("Hello " + customer.getName());
// Loop through each item and ask for qty desired
for (Product p : ProductList) {
do {
// Ask user for qty
System.out.println("How many would you like for product: " + p.name);
System.out.print("> ");
// Get input and set qty for the object
qty = scan.nextInt();
}
while (qty < 0); // Validation
p.setQty(qty); // Set qty for object
qty = 0; // Reset count
}
// Cleanup
scan.close();
}
public static void PromptCustomerPayment (Customer customer) {
// Initiate Scanner
Scanner sc = new Scanner(System.in);
// Variables
String payment = "";
// Prompt User
do {
System.out.println("Would you like to pay in full? [Yes/No]");
System.out.print("> ");
payment = sc.next();
} while ((!payment.toLowerCase().equals("yes")) && (!payment.toLowerCase().equals("no")));
// Check/set result
if (payment.toLowerCase() == "yes") {
customer.setPaidInFull(true);
}
else {
customer.setPaidInFull(false);
}
// Cleanup
sc.close();
}
Ответы
Ответ 1
Это действительно озадачило меня некоторое время, но это то, что я нашел в конце.
Когда вы вызываете, sc.close()
в первом методе, он не только закрывает ваш сканер, но также закрывает поток ввода System.in
. Вы можете проверить его, распечатав его статус в верхней части второго метода, как:
System.out.println(System.in.available());
Итак, теперь, когда вы повторно создаете экземпляр, Scanner
во втором методе, он не находит открытого потока System.in
и, следовательно, исключения.
Я сомневаюсь, что есть какой-либо выход для открытия System.in
, потому что:
public void close() throws IOException --> Closes this input stream and releases any system resources associated with this stream. The general contract of close is that it closes the input stream. A closed stream cannot perform input operations and **cannot be reopened.**
Единственное хорошее решение для вашей проблемы - инициировать Scanner
в своем основном методе, передать это как аргумент в двух ваших методах и снова закрыть его в своем основном методе, например:
main
связанный с кодом блок кода:
Scanner scanner = new Scanner(System.in);
// Ask users for quantities
PromptCustomerQty(customer, ProductList, scanner );
// Ask user for payment method
PromptCustomerPayment(customer, scanner );
//close the scanner
scanner.close();
Ваши методы:
public static void PromptCustomerQty(Customer customer,
ArrayList<Product> ProductList, Scanner scanner) {
// no more scanner instantiation
...
// no more scanner close
}
public static void PromptCustomerPayment (Customer customer, Scanner sc) {
// no more scanner instantiation
...
// no more scanner close
}
Надеюсь, это даст вам некоторое представление о неудаче и возможном разрешении.
Ответ 2
Проблема
Когда сканер закрыт, он закроет свой входной источник, если источник реализует интерфейс Closeable.
http://docs.oracle.com/javase/1.5.0/docs/api/java/util/Scanner.html
Таким образом, scan.close()
закрывает System.in
.
Чтобы исправить это, вы можете сделать
Scanner scan
static
и не закрывайте его в PromptCustomerQty. Ниже приведен код ниже.
public static void main (String[] args) {
// Create a customer
// Future proofing the possabiltiies of multiple customers
Customer customer = new Customer("Will");
// Create object for each Product
// (Name,Code,Description,Price)
// Initalize Qty at 0
Product Computer = new Product("Computer","PC1003","Basic Computer",399.99);
Product Monitor = new Product("Monitor","MN1003","LCD Monitor",99.99);
Product Printer = new Product("Printer","PR1003x","Inkjet Printer",54.23);
// Define internal variables
// ## DONT CHANGE
ArrayList<Product> ProductList = new ArrayList<Product>(); // List to store Products
String formatString = "%-15s %-10s %-20s %-10s %-10s %n"; // Default format for output
// Add objects to list
ProductList.add(Computer);
ProductList.add(Monitor);
ProductList.add(Printer);
// Ask users for quantities
PromptCustomerQty(customer, ProductList);
// Ask user for payment method
PromptCustomerPayment(customer);
// Create the header
PrintHeader(customer, formatString);
// Create Body
PrintBody(ProductList, formatString);
}
static Scanner scan;
public static void PromptCustomerQty(Customer customer, ArrayList<Product> ProductList) {
// Initiate a Scanner
scan = new Scanner(System.in);
// **** VARIABLES ****
int qty = 0;
// Greet Customer
System.out.println("Hello " + customer.getName());
// Loop through each item and ask for qty desired
for (Product p : ProductList) {
do {
// Ask user for qty
System.out.println("How many would you like for product: " + p.name);
System.out.print("> ");
// Get input and set qty for the object
qty = scan.nextInt();
}
while (qty < 0); // Validation
p.setQty(qty); // Set qty for object
qty = 0; // Reset count
}
// Cleanup
}
public static void PromptCustomerPayment (Customer customer) {
// Variables
String payment = "";
// Prompt User
do {
System.out.println("Would you like to pay in full? [Yes/No]");
System.out.print("> ");
payment = scan.next();
} while ((!payment.toLowerCase().equals("yes")) && (!payment.toLowerCase().equals("no")));
// Check/set result
if (payment.toLowerCase() == "yes") {
customer.setPaidInFull(true);
}
else {
customer.setPaidInFull(false);
}
}
На стороне примечания, вы не должны использовать ==
для сравнения строк, вместо этого используйте .equals
.
Ответ 3
После этой строки:
qty = scan.nextInt();
Всегда добавляйте еще одну строку для очистки сканера:
scan.nextLine();
Кроме того, используйте
sc.nextLine();
вместо
sc.next();