Бесконечный цикл while не получает входные данные от сканера после первого выполнения [duplicate]

Ну, аннотация, документирующая намерение, была бы бесполезной, если вы предполагаете, что всегда есть это намерение.

Вы назвали пример AutoCloseable, который, очевидно, не предназначен который будет реализован как функция, так как существует Runnable, что намного удобнее для функции с сигнатурой ()->void. Предполагается, что класс, реализующий AutoCloseable, управляет внешним ресурсом, который анонимные классы, реализованные с помощью лямбда-выражения, не выполняет.

Более ясным примером является Comparable, а interface не только не предназначено реализованный в виде лямбда-выражения, невозможно реализовать его правильно с использованием лямбда-выражения.


Возможные причины не отмечать interface с помощью @FunctionalInterface на примере:

  • interface имеет семантику языка программирования, например AutoClosable или Iterable (это вряд ли произойдет для ваших собственных интерфейсов)
  • Не ожидается, что interface имеет произвольные реализации и / или больше идентификатор, чем фактическая реализация, например. java.net.ProtocolFamily или java.lang.reflect.GenericArrayType (обратите внимание, что последний также наследует реализацию default для getTypeName(), которая бесполезна для лямбда-реализаций, полагаясь на toString())
  • . Случаи этого interface ] должны иметь личность, например java.net.ProtocolFamily, java.nio.file.WatchEvent.Modifier и т. д. Обратите внимание, что они обычно реализуются с помощью enum. Другим примером является java.time.chrono.Era, который имеет только один метод abstract, но его спецификация говорит: Экземпляры Era можно сравнить с помощью оператора ==. »
  • interface предназначен для изменения поведения операции, для которой реализация interface не наследует / реализует что-либо иначе не имеет смысла, например java.rmi.server.Unreferenced
  • Это абстракция общих операций классов, которые должны иметь не только эти операции, например. java.io.Closeable, java.io.Flushable, java.lang.Readable
  • Ожидаемое наследование является частью контракта и запрещает реализацию лямбда-выражения, например. в java.awt: ActiveEvent должен быть реализован с помощью AWTEvent, PrinterGraphics на Graphics, то же самое относится к java.awt.print.PrinterGraphics (эй, два interface s для точно такой же вещи ...), javax.print.FlavorException должен быть реализован подклассом javax.print.PrintException
  • Я не знаю, не связаны ли различные интерфейсы прослушивателя событий с @FunctionalInterface для симметрии с другим прослушивателем событий нескольких методов, t функциональные интерфейсы, но на самом деле прослушиватели событий являются хорошими кандидатами на лямбда-выражения. Если вы хотите удалить слушателя позднее, вы должны сохранить экземпляр, но это не отличается от, например, (g12)
  • У хранителя библиотеки есть большая база кода с более чем 200 типами кандидатов, а не ресурсы для обсуждения для каждого interface, следует ли ее аннотировать и, следовательно, сосредоточить внимание на основных кандидатах на то, чтобы быть используется в функциональном контексте. Я уверен, что, например, java.io.ObjectInputValidation, java.lang.reflect.InvocationHandler, juc RejectedExecutionHandler & amp; ThreadFactory не будет плохой как @FunctionalInterface, но я не знаю, будет ли, например. java.security.spec.ECField делает хорошего кандидата. Чем более общей является библиотека, тем более вероятным пользователям библиотеки будет возможность ответить на этот вопрос для конкретного interface, который им интересен, но было бы несправедливо настаивать на том, чтобы разработчик библиотеки ответил на него для все . В этом контексте имеет смысл видеть присутствие @FunctionalInterface в качестве сообщения о том, что interface определенно предназначено для использования вместе с лямбда-выражениями, чем рассматривать отсутствие аннотации в качестве индикатора того, что он не предназначен для использования таким образом. Это точно так же, как компилятор справляется с этим, вы можете реализовать каждый абстрактный метод interface с использованием лямбда-выражения, но когда присутствует аннотация, гарантирует , что вы можете использовать этот interface в этом путь.

40
задан fortune 24 October 2012 в 03:04
поделиться

3 ответа

Это действительно озадачило меня какое-то время, но это то, что я нашел в конце.

Когда вы вызываете 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
 }

Надеюсь, это даст вам некоторое представление о сбое и возможном разрешении.

95
ответ дан Half Genius 4 September 2018 в 10:34
поделиться

После этой строки:

qty = scan.nextInt();

Всегда добавляйте еще одну строку для очистки сканера:

scan.nextLine();

Кроме того, используйте

sc.nextLine();

вместо

sc.next();
0
ответ дан Lai Xin Chu 4 September 2018 в 10:34
поделиться

Проблема заключается в

Когда сканер закрыт, он закрывает свой входной источник, если источник реализует интерфейс 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.

17
ответ дан user 4 September 2018 в 10:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: