java.util.NoSuchElementException - 扫描器读取用户输入

2022-01-30 00:00:00 input java java.util.scanner

我是使用 Java 的新手,但我以前使用过 C#.我遇到的问题是从控制台读取用户输入.

I'm new to using Java, but I have some previous experience with C#. The issue I'm having comes with reading user input from console.

我遇到了java.util.NoSuchElementException".这部分代码出错:

I'm running into the "java.util.NoSuchElementException" error with this portion of code:

payment = sc.next(); // PromptCustomerPayment function

我有两个获取用户输入的函数:

I have two functions that get user input:

  • 提示客户数量
  • 提示客户付款

如果我不调用 PromptCustomerQty,则不会收到此错误,这使我相信我在扫描仪上做错了.下面是我的完整代码示例.感谢您的帮助.

If I don't call PromptCustomerQty then I don't get this error, which leads me to believe I am doing something wrong with scanner. Below is my full code sample. I appreciate any help.

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(); 
}

推荐答案

这确实让我困惑了一段时间,但这是我最终找到的.

当您在第一种方法中调用 sc.close() 时,它不仅会关闭您的扫描仪,还会关闭您的 System.in 输入流.您可以通过在第二种方法的最顶部打印其状态来验证它:

When you call, sc.close() in first method, it not only closes your scanner but closes your System.in input stream as well. You can verify it by printing its status at very top of the second method as :

    System.out.println(System.in.available());

所以,现在当您在第二种方法中重新实例化 Scanner 时,它不会找到任何打开的 System.in 流,因此会出现异常.

So, now when you re-instantiate, Scanner in second method, it doesn't find any open System.in stream and hence the exception.

我怀疑是否有办法重新打开 System.in 因为:

I doubt if there is any way out to reopen System.in because:

public void close() throws IOException -->关闭此输入流并释放与此流关联的所有系统资源.close 的一般约定是它关闭输入流.关闭的流无法执行输入操作,并且**无法重新打开.**

解决您的问题的唯一好方法是在您的 main 方法中启动 Scanner,将其作为参数传递给您的两个方法,然后在您的 main 方法中再次关闭它,例如:

The only good solution for your problem is to initiate the Scanner in your main method, pass that as argument in your two methods, and close it again in your main method e.g.:

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
 }

希望这能让您对失败和可能的解决方案有所了解.

Hope this gives you some insight about the failure and possible resolution.

相关文章