2012-10-24 18 views
35

Jestem nowy w używaniu języka Java, ale mam pewne wcześniejsze doświadczenia z C#. Problem, który mam, polega na czytaniu danych wprowadzanych przez użytkownika z konsoli.java.util.NoSuchElementException - Odczytywanie przez skanera danych wprowadzanych przez użytkownika

biegnę do "java.util.NoSuchElementException" błąd z tego fragmentu kodu:

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

Mam dwie funkcje, które uzyskać dane wejściowe użytkownika:

  • PromptCustomerQty
  • PromptCustomerPayment

Jeśli nie zadzwonię do PromptCustomerQty, to nie będę t ten błąd, który prowadzi mnie do przekonania, że ​​robię coś złego ze skanerem. Poniżej znajduje się moja pełna próbka kodu. Doceniam każdą pomoc.

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

Odpowiedz

86

To naprawdę mnie zdziwiło przez chwilę, ale to właśnie znalazłem na końcu.

Po wywołaniu, sc.close() w pierwszej metodzie, nie tylko zamyka skaner, ale także zamyka strumień wejściowy System.in.Można go zweryfikować drukując swój status na samym szczycie drugiej metody, jak:

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

Więc teraz, gdy ponownie instancję, Scanner w drugiej metodzie, nie znaleziono żadnej otwartej System.in strumienia i stąd wyjątek.

Wątpię, czy istnieje jakiś sposób się do ponownego System.in ponieważ:

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.**

Jedynym dobrym rozwiązaniem Twojego problemu jest, aby zainicjować Scanner w głównej metody, które przechodzą jako argument w twojej dwa metody i zamknąć go ponownie w metodzie Main np

main metoda kod związany bloku:

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

Twoje Metody:

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 
} 

Nadzieja daje to pewne wyobrażenie o awarii i możliwej rozdzielczości.

+4

Dziękuję za odpowiedź. Twoje wyjaśnienie tego, co dzieje się za kulisami, jest bardzo pomocne. – fortune

+0

Dziękuję za odpowiedź. To prawda! – d3vpasha

+0

O mój boże, utknąłem tak długo, aż znalazłem ten post. Dziękuję bardzo! Jesteś niesamowity. –

15

Problemem jest

Jeśli skaner jest zamknięty, to zamknięcie jego sygnał wejściowy, jeżeli źródło realizuje zamykaną interfejs.

http://docs.oracle.com/javase/1.5.0/docs/api/java/util/Scanner.html

Zatem scan.close() zamyka System.in.

Aby rozwiązać go można dokonać

Scanner scanstatic i nie zamykaj go w PromptCustomerQty. Kod poniżej działa.

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

Na marginesie, nie należy używać == dla porównania String, użyj zamiast .equals.

+0

Ale są one w różnych metodach, prawda? Gdzie są tworzone i zamykane. –

+0

W oryginalnym kodzie są. W stałym kodzie używam jednej instancji skanera dla obu metod. –

+0

Nadal jestem zdziwiony, dlaczego 'sc.next()' lub nawet 'sc.nextLine()' w drugiej metodzie powodują wyjątek. –

0

Po tej linii:

qty = scan.nextInt(); 

Zawsze dodać jeszcze jedną linię, aby wyczyścić skaner:

scan.nextLine(); 

także skorzystać

sc.nextLine(); 

zamiast

sc.next(); 
+0

Dodano scan.nextLine(); i zmieniłem sc.next() na sc.nextLine() ;, ale wciąż dostaję błąd. – fortune

Powiązane problemy