Throwing Exceptions and Cleaning Up
So far we have caught exceptions that the library threw. Brew Bar's own rules need the same power: an order for 50 cups, or a drink that has run out, should stop the operation with a clear message. And the receipt printer must always be released, however the order ends.
The rule
Throw where it breaks, catch where you can fix it.
The method that discovers a problem is usually the wrong place to decide what to do about it. So it throws, and a caller higher up, such as the screen that can show a message, catches:
public void addCups(int extra) {
if (extra < 1 || cups + extra > MAX_CUPS) {
throw new IllegalArgumentException("cups must stay between 1 and " + MAX_CUPS);
}
cups += extra;
}Keep the two keywords apart: throw (in the body) actually throws one exception object; throws (in the header) declares that a method might let one escape.
When no standard exception describes your situation, create your own by extending an existing class:
public class OutOfStockException extends Exception {
public OutOfStockException(String drink) {
super(drink + " is out of stock");
}
}Extend Exception for a checked exception, when callers should be forced to plan for it, as with running out of oat milk. Extend RuntimeException for an unchecked one, typically for misuse of your class. A named exception type lets callers catch exactly this problem and nothing else.
For clean-up, try-with-resources is better than a hand-written finally. Anything that implements AutoCloseable, such as files, network connections or Brew Bar's ReceiptPrinter, can be opened in brackets after try, and Java closes it automatically:
try (ReceiptPrinter printer = new ReceiptPrinter();
CashDrawer drawer = new CashDrawer()) {
printer.print(order.receipt());
drawer.open();
} // drawer closes, then printer, even if an exception was thrownResources are closed in reverse order of opening, like stacking and unstacking plates.
The shortcut
For every rule a method enforces, ask "Can this method fix it?" If yes, fix it there. If no, throw a well-named exception with a clear message and let the caller who can respond catch it. For anything that must be closed, reach for try-with-resources by default.
Detect
Kitchen.make("Oat latte")finds no oat milk. It cannot conjure milk, so it cannot fix this.
Drills
Answer fast — trust the rule.
Which keyword appears in a method header to declare that an exception may escape?
class MachineJammedException extends RuntimeException is thrown by a method with no throws clause. Does it compile?
Each close method prints its class's initial, and nothing else prints except the body. What does try (Printer p = new Printer(); Drawer d = new Drawer()) { System.out.print("W"); } print?
What can be opened in the brackets of a try-with-resources?
Remember
- Throw where it breaks, catch where you can fix it.
throwthrows one object;throwsdeclares. Extend Exception for checked, RuntimeException for unchecked.- Use try-with-resources for anything closeable; it closes in reverse order.
