Ну, аннотация, документирующая намерение, была бы бесполезной, если вы предполагаете, что всегда есть это намерение.
Вы назвали пример 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) interface
, следует ли ее аннотировать и, следовательно, сосредоточить внимание на основных кандидатах на то, чтобы быть используется в функциональном контексте. Я уверен, что, например, java.io.ObjectInputValidation
, java.lang.reflect.InvocationHandler
, juc RejectedExecutionHandler
& amp; ThreadFactory
не будет плохой как @FunctionalInterface
, но я не знаю, будет ли, например. java.security.spec.ECField
делает хорошего кандидата. Чем более общей является библиотека, тем более вероятным пользователям библиотеки будет возможность ответить на этот вопрос для конкретного interface
, который им интересен, но было бы несправедливо настаивать на том, чтобы разработчик библиотеки ответил на него для все . В этом контексте имеет смысл видеть присутствие @FunctionalInterface
в качестве сообщения о том, что interface
определенно предназначено для использования вместе с лямбда-выражениями, чем рассматривать отсутствие аннотации в качестве индикатора того, что он не предназначен для использования таким образом. Это точно так же, как компилятор справляется с этим, вы можете реализовать каждый абстрактный метод interface
с использованием лямбда-выражения, но когда присутствует аннотация, гарантирует , что вы можете использовать этот interface
в этом путь. Это действительно озадачило меня какое-то время, но это то, что я нашел в конце.
Когда вы вызываете 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
}
Надеюсь, это даст вам некоторое представление о сбое и возможном разрешении.
После этой строки:
qty = scan.nextInt();
Всегда добавляйте еще одну строку для очистки сканера:
scan.nextLine();
Кроме того, используйте
sc.nextLine();
вместо
sc.next();
Проблема заключается в
Когда сканер закрыт, он закрывает свой входной источник, если источник реализует интерфейс Closeable.
blockquote>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
.