1. ホーム
  2. java

[解決済み】 java.util.NoSuchElementException - ユーザー入力を読み取るスキャナ

2022-02-11 02:20:26

質問

私はJavaを使うのは初めてですが、C#の使用経験はあります。私が抱えている問題は、コンソールからのユーザー入力を読み取ることにあります。

この部分のコードで "java.util.NoSuchElementException" というエラーに遭遇しています。

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

ユーザーの入力を得るための2つの関数があります。

  • プロンプトCustomerQty
  • プロンプトカスタマーペイメント

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

解決方法は?

これは本当にしばらく困惑していたのですが、最終的にこういうことがわかりました。

を呼び出すと。 sc.close() 最初のメソッドでは、スキャナを閉じるだけでなく System.in 入力ストリームも同様です。このことは、2番目のメソッドの一番上にある.NETの状態を表示することで確認できます。

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

では、次に再インスタンス化するとき。 Scanner を使用すると、2 番目のメソッドでは、開いている 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.**

あなたの問題に対する唯一の良い解決策は、「Space」を起動することです。 Scanner をメインメソッドで開き、それを2つのメソッドで引数として渡し、メインメソッドで再び閉じます(例)。

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
 }

これで、障害と可能な解決策について、何らかのヒントが得られると思います。