Study smarter with Fiveable
Get study guides, practice questions, and cheatsheets for all your subjects. Join 500,000+ students with a 96% pass rate.
Error handling separates amateur code from production-ready software. In Programming Languages and Techniques III, you're being tested on your ability to design robust systems that anticipate failure, respond gracefully, and maintain stability under unexpected conditions. This isn't just about catching exceptions—it's about understanding control flow, resource management, abstraction layers, and defensive programming as interconnected principles.
When you encounter error handling questions on exams, you're really being asked to demonstrate mastery of program architecture. Can you identify where exceptions should be caught versus propagated? Do you understand why certain resources require guaranteed cleanup? Can you design custom exception hierarchies that communicate meaningful information? Don't just memorize syntax—know why each practice exists and when to apply it.
Exception handling works best when you leverage the type system to communicate precise information about what went wrong. Generic catches obscure problems; specific catches enable targeted responses.
FileNotFoundException tells you exactly what failed, while catching Exception tells you almost nothingcatch (Exception e) might silently swallow OutOfMemoryError or NullPointerException that indicate serious bugscatch (Exception e) {}) are almost never acceptable in production codeCompare: Specific vs. Generic exception catching—both prevent crashes, but specific catches preserve diagnostic information and enable appropriate responses. If an exam question asks about debugging difficulty, generic catches are your go-to bad example.
The try-catch-finally construct provides a predictable control flow pattern for managing exceptional conditions. The key insight is separation of concerns: normal logic, error handling, and cleanup each have designated locations.
IOException, not Exceptiontry-with-resources (Java) or using statements (C#) that automate this patternCompare: Try-catch vs. finally blocks—try-catch handles the exception, finally handles cleanup. They solve different problems and are often used together. FRQ tip: if asked about resource leaks, always mention finally blocks or equivalent constructs.
Where you handle exceptions matters as much as how you handle them. Exceptions should be caught at the level where meaningful action can be taken—not too early (losing context) or too late (crashing the system).
Compare: Handling locally vs. propagating—local handling is appropriate when recovery is possible at that level; propagation is better when higher layers have more context for decision-making. Exam questions often test whether you can identify the appropriate handling level.
Standard exception types can't capture every error condition your application might encounter. Custom exceptions extend the type system to express domain-specific failure modes with precision.
InsufficientFundsException communicates more than IllegalStateExceptionPaymentException should probably extend RuntimeException or a domain-specific basepublic class InsufficientFundsException extends RuntimeException { private final BigDecimal requested; private final BigDecimal available; // Constructor and getters... }
Exceptions that occur in production need to be discoverable and diagnosable. Logging transforms transient runtime events into permanent records for analysis.
ERROR for failures requiring attention, WARN for recoverable issues, DEBUG for development diagnosticsCompare: Logging vs. displaying to users—logs should be verbose and technical for developers; user messages should be concise and actionable. Never expose stack traces in user-facing interfaces.
End users shouldn't experience the raw impact of system failures. Good error handling translates technical problems into understandable guidance while maintaining maximum functionality.
Compare: Recovery vs. graceful failure—recovery attempts to continue normal operation; graceful failure acknowledges the problem while minimizing user impact. Both are valid strategies depending on the error type and criticality.
| Concept | Best Practices |
|---|---|
| Exception Specificity | Use specific types, avoid generic catches, leverage type hierarchies |
| Structured Handling | Try-catch blocks, finally for cleanup, try-with-resources |
| Propagation Strategy | Throw at appropriate level, propagate to decision-makers, document exceptions |
| Custom Exceptions | Domain-specific types, additional context fields, proper inheritance |
| Observability | Detailed logging, appropriate severity levels, contextual data |
| User Experience | Friendly messages, hide technical details, fallback mechanisms |
| Recovery | Automatic retries, alternative workflows, data integrity preservation |
You're writing a method that reads configuration from a file. Should you catch IOException inside the method or let it propagate? What factors influence this decision?
Compare catch (Exception e) with catch (FileNotFoundException e) followed by catch (IOException e)—what information is lost with the generic approach, and how does this affect debugging?
A database connection is opened in a try block. Where should the connection.close() call be placed, and why does this placement matter even if no exception occurs?
When would you create a custom exception class rather than using a standard library exception? Give an example of domain-specific information your custom exception might carry.
Compare error messages appropriate for log files versus user interfaces when a payment processing system fails. What should each contain, and what should each omit?