Flashcards for topic Exceptions
What's wrong with the following loop pattern and why should it be avoided?
try { int i = 0; while(true) range[i++].climb(); } catch (ArrayIndexOutOfBoundsException e) { }
This code abuses exceptions for ordinary control flow - a serious anti-pattern because:
The proper alternative is a standard loop:
for (Mountain m : range) m.climb();
Exceptions should only be used for exceptional conditions, not regular control flow.
What is the "cardinal rule" for deciding between checked and unchecked exceptions, and what factors should influence this decision?
Cardinal rule: Use checked exceptions for conditions from which the caller can reasonably be expected to recover.
Decision factors:
Use checked exceptions when:
Use runtime exceptions when:
If it's unclear whether recovery is possible, favor unchecked exceptions.
Remember: Checked exceptions increase API complexity but enhance reliability when used appropriately.
Explain why overuse of checked exceptions in APIs can be problematic and describe two techniques to convert a checked exception into a more API-friendly alternative.
Problems with overusing checked exceptions:
Two conversion techniques:
// Instead of: public FileData readFile(File f) throws IOException { /*...*/ } // Consider: public Optional<FileData> readFile(File f) { try { // Read file return Optional.of(fileData); } catch (IOException e) { return Optional.empty(); } }
// Instead of one method throwing checked exception: public void action(Args args) throws CheckedException { /*...*/ } // Create two methods: public boolean actionPermitted(Args args) { /*...*/ } public void action(Args args) { // throws unchecked exception if needed if (!actionPermitted(args)) { throw new UncheckedExceptionVariant(); } // Perform action }
The second approach is inappropriate for concurrent access without synchronization.
What is the correct way to handle an exception that you intentionally want to ignore?
If you must ignore an exception:
ignored
to signal intentExample:
Future<Integer> f = exec.submit(planarMap::chromaticNumber); int numColors = 4; // Default; guaranteed sufficient for any map try { numColors = f.get(1L, TimeUnit.SECONDS); } catch (TimeoutException | ExecutionException ignored) { // Use default: minimal coloring is desirable, not required // Logging might be appropriate here for monitoring }
What is the relationship between API documentation and failure atomicity? What should happen when this rule is violated?
Relationship:
When violated:
Unfortunately, many existing APIs fail to properly document these behaviors, leading to unpredictable behavior when exceptions occur.
What strategies can be used to achieve failure atomicity in methods?
Strategies for achieving failure atomicity (ensuring objects remain in a consistent state after exception):
Design immutable objects (Item 17)
Check parameters before performing operations
Order computations to fail before modifications
Make temporary copies of mutable data
Recovery code in catch blocks
Write robust catch-finally blocks
Failure atomicity is especially important for checked exceptions, from which callers are expected to recover.
What are the best practices for documenting exceptions in Java APIs?
Best practices for documenting exceptions:
Document all exceptions, both checked and unchecked
Declare each checked exception individually in the throws clause
Document precisely when each exception is thrown
For interface methods, document unchecked exceptions thoroughly
For multiple methods throwing the same exception for the same reason:
Distinguish between checked and unchecked exceptions in documentation
Remember: Undocumented exceptions make it difficult or impossible for others to effectively use your classes and interfaces.
What technique should be used to create exception classes that automatically generate high-quality detail messages?
Technique for automatically generating high-quality detail messages in exceptions:
Implementation example:
public class RangeException extends RuntimeException { private final double minimum; private final double maximum; private final double value; /** * Creates an exception when a value is outside an allowed range. * * @param minimum The minimum allowed value * @param maximum The maximum allowed value * @param value The actual value provided */ public RangeException(double minimum, double maximum, double value) { // Generate a detailed message automatically super(String.format( "Value %f is outside allowed range [%f, %f]", value, minimum, maximum)); // Save parameters for programmatic access this.minimum = minimum; this.maximum = maximum; this.value = value; } // Accessor methods public double getMinimum() { return minimum; } public double getMaximum() { return maximum; } public double getValue() { return value; } }
Benefits:
Explain why an object might not be usable after catching a ConcurrentModificationException
, and what this teaches us about failure atomicity guarantees.
When a ConcurrentModificationException
occurs:
Key insight about failure atomicity: Failure atomicity cannot be guaranteed in scenarios involving concurrency violations. This demonstrates an important limitation - atomicity guarantees only apply when the client follows the object's usage contract. When multiple threads modify an object without proper synchronization, the responsibility for maintaining consistency shifts to the client code.
This teaches us that failure atomicity is a conditional guarantee that depends on proper usage patterns.
What are the standard Java exceptions you should reuse in your APIs, when is each appropriate, and what benefits do they provide over custom exceptions?
IllegalArgumentException
IllegalStateException
NullPointerException
IndexOutOfBoundsException
ConcurrentModificationException
UnsupportedOperationException
Important: Only reuse an exception if your use case precisely matches its documented semantics, not just based on its name.
Showing 10 of 34 cards. Add this deck to your collection to see all cards.