提问人:fortune 提问时间:10/24/2012 最后编辑:Ivarfortune 更新时间:3/4/2023 访问量:156015
java.util.NoSuchElementException - 扫描程序读取用户输入
java.util.NoSuchElementException - Scanner reading user input
问:
我是使用 Java 的新手,但我以前有一些使用 C# 的经验。我遇到的问题是从控制台读取用户输入。
我在使用这部分代码时遇到“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().equals("yes")) {
customer.setPaidInFull(true);
}
else {
customer.setPaidInFull(false);
}
// Cleanup
sc.close();
}
答:
问题是
当 Scanner 关闭时,如果源实现了 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
评论
sc.next()
sc.nextLine()
java.util.NoSuchElementException: No line found
这真的让我困惑了一段时间,但这就是我最终发现的。
当您调用时,在第一种方法中,它不仅会关闭扫描程序,还会关闭输入流。您可以通过在第二种方法的最顶部打印其状态来验证它: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.**
解决您的问题的唯一好方法是在 main 方法中启动,在两个方法中将其作为参数传递,然后在 main 方法中再次关闭它,例如: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
}
希望这能让您对故障和可能的解决方案有所了解。
评论
您需要删除扫描仪的结束行:scan.close();
它以前发生在我身上,这就是原因。
异常的原因已经解释过,但是建议的解决方案并不是最好的。
您应该创建一个类,该类使用单一实例模式将 Scanner 保持为私有,从而使该扫描程序在您的代码中是唯一的。
然后你可以实现你需要的方法,或者你可以创建一个getScanner(不推荐),你可以用一个私有的布尔值来控制它,比如alreadyClosed。
如果您不知道如何使用单例模式,下面是一个示例:
public class Reader {
private Scanner reader;
private static Reader singleton = null;
private boolean alreadyClosed;
private Reader() {
alreadyClosed = false;
reader = new Scanner(System.in);
}
public static Reader getInstance() {
if(singleton == null) {
singleton = new Reader();
}
return singleton;
}
public int nextInt() throws AlreadyClosedException {
if(!alreadyClosed) {
return reader.nextInt();
}
throw new AlreadyClosedException(); //Custom exception
}
public double nextDouble() throws AlreadyClosedException {
if(!alreadyClosed) {
return reader.nextDouble();
}
throw new AlreadyClosedException();
}
public String nextLine() throws AlreadyClosedException {
if(!alreadyClosed) {
return reader.nextLine();
}
throw new AlreadyClosedException();
}
public void close() {
alreadyClosed = true;
reader.close();
}
}
对于在 HackerRank 等网站上参加在线考试时来到这里的任何人——
如果您尝试通过单击按钮以使用自定义输入执行 main() 来测试您的(可能)完美无缺的代码,您可能会收到此消息。
在这种情况下,您需要单击另一个按钮,例如“运行单元测试”。你可能只根据代码是否通过了他们编写的单元测试来评估,而不是你是否有能力将代码重构为更少的 LOC 或你的编码风格。
找到这个线程是因为我遇到了同样的问题。从这里找到原因后,我发现一种有用的方法是将单独的扫描仪对象用于不同的用途(因为如果使用单个扫描仪对象进行多个输入,则会有问题),然后在所有扫描仪对象使用完毕后关闭所有扫描仪对象。为更清晰的代码而制作,之后没有遇到任何问题。
评论