Exam objective 4.1 for the 1Z0-829 exam is all about handling the unexpected. This chapter explains 'Exceptions and Assertions', two tools that act as safety nets for your Java programs, ensuring they crash gracefully when something goes wrong or alert you to programming mistakes during development.
Jump to a section
A simple way to picture Exceptions and Assertions
Have you ever been cooking a big meal and suddenly run out of a key ingredient?
You are running a busy pizza kitchen on a Friday night. Your 'main program' is making a classic Margherita pizza: take the dough, spread the sauce, add the mozzarella, bake it, and serve. Normally, this flow works perfectly. But what happens if the delivery truck didn't bring any mozzarella? You cannot just keep going — the pizza would be ruined. In programming, this is an 'exception': something unexpected that breaks the normal flow of your recipe.
In a well-run kitchen, you don't just crash. You have a backup plan. When you discover there is no mozzarella, you 'catch' that problem and switch to making a Marinara pizza (which uses only tomato sauce) or you call the supplier to rush an order. This 'catching' is exactly what a try-catch block does in Java — it lets your program handle the missing ingredient instead of shutting down the whole restaurant.
Now, what about 'assertions'? Imagine you have a rule written on the wall: 'Every pizza must have exactly 8 slices when it leaves the kitchen.' If a chef tries to send out a 7-slice pizza, that is a serious mistake that should never happen in a properly debugged kitchen. An assertion is that note on the wall — it checks a condition during development (like the slice count) and screams loudly if it is false, because if it is false, your kitchen logic is fundamentally broken. Assertions are not for handling delivery failures; they are for catching your own internal cooking errors.
In Java, an exception is an event that disrupts the normal flow of a program's instructions. Think of the Java Virtual Machine (JVM) as a factory floor manager who follows each line of your code step by step. Normally, the manager executes doThis(), then doThat(), then doTheOther(). But if doThis() tries to open a file that does not exist, the manager cannot just shrug and move on — the instruction is impossible to complete. Instead, the manager creates a special object called an exception (like a red alert token) and 'throws' it into the execution environment. If your code does not have a mechanism to 'catch' that token, the program crashes.
The core tools for handling exceptions are try, catch, and finally blocks. You wrap risky code inside a try block. For example:
try {
int result = 10 / 0; // This will cause an ArithmeticException
} catch (ArithmeticException e) {
System.out.println("Cannot divide by zero!");
}If an exception occurs inside the try block, the JVM immediately jumps to the matching catch block. The catch block is like your pre-planned recovery room for that specific type of red alert. A try can have multiple catch blocks to handle different exception types. Since Java 7, you can use a multi-catch clause: catch (IOException | SQLException e) to handle multiple exception types in one block if their handling logic is identical.
There is also the finally block. A finally block always executes, whether an exception was thrown or not. It is like the clean-up crew that locks the doors after the concert ends, even if a fire alarm forced everyone out early. You use finally to release resources, like closing a file or a database connection.
Then there is the try-with-resources statement, introduced in Java 7 and enhanced in Java 9. This is a specialised try block that automatically closes resources that implement the AutoCloseable interface. You declare the resources in parentheses after try. For example:
try (FileReader fr = new FileReader("data.txt");
BufferedReader br = new BufferedReader(fr)) {
// read file content
} catch (IOException e) {
// handle errors
}The try-with-resources block calls the close() method on each resource automatically at the end, even if an exception occurs. This replaces the old, error-prone pattern of manually closing resources in a finally block. It is cleaner and prevents resource leaks.
Now, assertions are a different tool. An assertion is a statement that you use to verify that a condition you believe to be true is actually true. You use it with the assert keyword: assert age >= 0 : "Age must be non-negative";. If age is -5, the assertion throws an AssertionError. Assertions are disabled by default at runtime. You enable them with a command-line flag (-ea). They are meant for development and testing, not for production. You should never rely on assertions for argument validation in public methods; that is what IllegalArgumentException (a standard exception) is for. Assertions check your program's internal assumptions — like ensuring a switch statement's default branch is never reached, or that a variable has been initialised before use.
Identify Risky Code
Look through your method and locate any line of code that could cause an exception. Common sources are file I/O (FileReader, BufferedReader), network operations (Socket connections), database calls (JDBC queries), and mathematical operations that divide by zero. These are the lines that need protection.
Wrap in a Try Block
Surround the risky code with a `try { ... }` block. This tells the JVM: 'Execute this code, and if something goes wrong, I am ready to handle it.' You can put multiple risky statements in one try block if they are related (e.g., opening and reading a file).
Catch Specific Exceptions
Add one or more `catch` blocks immediately after the try block. Each catch block specifies the exception type it handles (e.g., `catch (IOException e)`). Place more specific exceptions (like FileNotFoundException) before more general ones (like IOException). If the order is wrong, the code will not compile.
Add a Finally Block (if needed)
If you are not using try-with-resources and you have opened a resource (like a file stream or a database connection), add a `finally { }` block after the catch blocks to close it. The finally block always executes, so it is the safest place to release resources.
Use Try-With-Resources When Possible
If a resource class implements AutoCloseable (like BufferedReader or FileWriter), declare it in parentheses after the try keyword: `try (BufferedReader br = new BufferedReader(...))`. This eliminates the need for a finally block to close the resource. The resource is closed automatically at the end of the try block.
Enable Assertions During Testing
To use assertions in your code, write `assert condition : "message";`. Run your program with the `-ea` (enable assertions) flag in the command line: `java -ea MyProgram`. Without this flag, assert statements are completely ignored and have zero runtime cost.
An IT professional writing a banking application for an online payment system uses exceptions constantly. Consider a function that transfers money from one account to another. The normal flow is: check the sender has enough balance, debit the sender, credit the recipient, and log the transaction. But reality is messy.
Step one: the system tries to connect to the database to read the sender's balance. The database server might be down. This throws an SQLException. The developer wraps the database connection code in a try block. The catch block logs the error and sends a 'temporary outage' message to the customer, rather than crashing the entire ATM network.
Step two: the debit operation might fail because of a unique constraint violation (e.g. a duplicate transaction ID). The developer catches a DataIntegrityViolationException and retries with a new transaction ID.
Step three: after debiting the sender, what if the credit to the recipient fails? This is a critical issue — the sender lost money but the recipient did not receive it. The developer must handle this with a transaction rollback. This is often done with the try-with-resources pattern on a database connection, ensuring the transaction is rolled back in the catch or finally block. The finally block is essential here to close the database connection cleanly, even if an error occurred.
Assertions are used differently. A senior developer might write a utility method that calculates the interest rate based on account type. The method has a switch block for account types: SAVINGS, CHECKING, and INVESTMENT. The developer adds a default case not to handle a valid type, but to catch a programming mistake:
switch (accountType) {
case SAVINGS: return 0.02;
case CHECKING: return 0.01;
case INVESTMENT: return 0.05;
default: assert false : "Unknown account type: " + accountType;
}If a new account type is added later but the switch is not updated, the assertion fires during testing, alerting the team immediately.
In practice, an IT professional writes unit tests that enable assertions. They run the code with the -ea flag in their local development environment and on the continuous integration server. They do not ship the code with assertions enabled in production because assertions can be turned off (and usually are) for performance reasons. They rely on standard exceptions and logging for production issues.
The workflow for a developer handling exceptions involves:
Identifying all risky operations in a method (file I/O, network calls, database queries, user input parsing).
Wrapping them in try blocks.
Catching specific exception types, not the generic Exception class, to handle different failures differently.
Using finally blocks for mandatory clean-up when not using try-with-resources.
Using try-with-resources for any object that implements AutoCloseable, such as file streams, network sockets, and database connections.
Logging exceptions with enough context (the stack trace, the user's input, the state of the system) so that the operations team can diagnose issues later.
Throwing custom exceptions (e.g., InsufficientFundsException) to provide clear, business-specific error messages to the calling code.
The 1Z0-829 exam tests 'Exceptions and Assertions' in a specific, predictable way. You need to know exactly what the examiners look for and the traps they set.
Here are the core exam topics tested under objective 4.1:
The hierarchy of exception classes: Throwable, Exception, RuntimeException, Error.
Checked vs unchecked (runtime) exceptions. Which ones are checked? (IOException, SQLException). Which are unchecked? (NullPointerException, IllegalArgumentException).
The syntax of try-catch-finally blocks, including multi-catch.
The order of catch blocks: subclasses must come before superclasses, or the code will not compile.
The try-with-resources statement: the syntax, the requirement that resources must implement AutoCloseable or Closeable, and how multiple resources are handled.
The fact that a catch or finally block is not always required in a try-with-resources (though usually one or the other is present).
The throw keyword vs the throws keyword. 'throw' is an action inside a method; 'throws' is a declaration on the method signature.
Custom exception classes: creating your own exception by extending Exception (for checked) or RuntimeException (for unchecked).
Assertions: the assert syntax, the default disabled state, the -ea flag, and the fact that you should not use assertions to validate arguments in public methods.
Traps to watch out for:
'Checked exceptions not handled or declared': The exam presents code that throws a checked exception but does not catch it or declare it with throws. The answer is 'Does not compile'.
'Finally block returning a value': If both a catch block and a finally block have return statements, the finally return overrides the catch return. This is a classic trick question.
'Multi-catch variable is effectively final': In a multi-catch clause like catch (IOException | SQLException e), the variable e is implicitly final. You cannot reassign it.
'Assertions with side effects': The exam may have assert someMethod(). If assertions are disabled, someMethod() never runs. This can be a performance trap.
'Resource ordering in try-with-resources': Resources are closed in the reverse order of their declaration.
'The throw terminator': The throw keyword terminates the current execution flow. Code after a throw statement is unreachable unless enclosed in a conditional.
Key definitions to memorise:
'Throwable': the superclass of all errors and exceptions.
'Exception': the superclass of all conditions that a reasonable application might want to catch.
'RuntimeException': an exception that does not need to be checked or declared.
'Error': a serious problem that a reasonable application should not try to catch (e.g., OutOfMemoryError, StackOverflowError).
'assert': a keyword used to test assumptions during development.
An exception is an event that disrupts the normal flow of a program and is represented by an object of the Throwable class or one of its subclasses.
Use try-catch blocks to handle exceptions gracefully, and always catch the most specific exception type for the situation.
The finally block always executes after the try block, regardless of exception occurrence, making it ideal for releasing system resources.
Try-with-resources automatically closes any resource that implements the AutoCloseable interface, replacing the need for explicit finally blocks in most cases.
Assertions using the assert keyword are used to verify internal invariants during development and are disabled by default at runtime.
Checked exceptions must be either caught in a try-catch block or declared in the method signature using the throws keyword; unchecked exceptions (RuntimeException and its subclasses) have no such requirement.
Multi-catch using the pipe symbol (|) allows you to handle multiple unrelated exception types in a single catch block, but the catch variable is implicitly final.
Custom exceptions are created by extending Exception (for checked) or RuntimeException (for unchecked) and allow you to define business-specific error conditions.
These come up on the exam all the time. Here's how to tell them apart.
Checked Exception
Must be either caught or declared in the method signature using 'throws'.
Examples include IOException, SQLException, ClassNotFoundException.
The compiler enforces handling at compile time.
Unchecked Exception (RuntimeException)
Does not need to be caught or declared (though you can if you want).
Examples include NullPointerException, ArithmeticException, ArrayIndexOutOfBoundsException.
The compiler does not enforce handling; it is the programmer's responsibility to avoid them.
try-catch-finally
Requires explicit finally block to close resources.
Can be used with any code block, regardless of whether resources are used.
More verbose and prone to resource leaks if the programmer forgets to close in finally.
try-with-resources
Automatically closes each resource that implements AutoCloseable when the try block exits.
Only works for resources declared in the parentheses after the try keyword.
Less verbose and more reliable for resource management.
throw keyword
Used inside a method body to actually cause an exception.
Followed by an instance of Throwable (e.g., throw new Exception()).
Creates the exception object and hands it to the runtime system.
throws keyword
Used in a method signature to declare that the method might throw an exception.
Followed by one or more exception class names (e.g., throws IOException, SQLException).
Tells the caller: 'You must handle or declare this exception.'
Exception (class)
Represents conditions that an application might want to catch (e.g., file not found, network timeout).
Superclass of both checked and unchecked exceptions for recoverable issues.
Can be caught and handled by the program.
Error (class)
Represents serious problems that a reasonable application should not try to catch (e.g., OutOfMemoryError, StackOverflowError).
Subclass of Throwable, separate from Exception.
Typically indicates unrecoverable JVM-level failures.
Mistake
The 'finally' block only runs if an exception is thrown.
Correct
The 'finally' block always runs after the try block, regardless of whether an exception was thrown or caught, unless the JVM shuts down abruptly (e.g., System.exit()).
This confusion comes from the name 'finally' which sounds like it means 'in the end, after handling the exception', but its purpose is unconditional clean-up.
Mistake
You should catch 'Exception' or 'Throwable' in every catch block to ensure you never miss an error.
Correct
In production code, you should catch the most specific exception type possible. Catching generic 'Exception' can hide bugs and make code harder to maintain. Catching 'Throwable' is even worse because it catches fatal Errors that should crash the program.
Beginners want a 'catch-all' safety net, but good programming requires handling different failures differently.
Mistake
Assertions are a good way to validate user input in a public method.
Correct
Assertions are for internal invariants and should not be used for input validation in public methods because they can be disabled. Use standard exceptions like IllegalArgumentException for input validation.
The syntax of assert seems like a simple validation check, so beginners think it replaces if-statements for validation. But disabling assertions would disable necessary security checks.
Mistake
A try-with-resources block automatically catches all exceptions thrown by the resource's close() method.
Correct
Try-with-resources automatically closes the resources, but if the close() method throws an exception, it is suppressed. You need to handle those suppressed exceptions separately using getSuppressed() on the main exception, or they can be caught in a catch block attached to the try-with-resources.
The phrase 'automatically handles resources' gives a false sense of simplicity. The exception handling of close() is nuanced.
Mistake
You can throw any object using the throw keyword.
Correct
You can only throw objects that are instances of Throwable or its subclasses (i.e., Throwable, Error, Exception, or their subclasses). You cannot throw a String or an int.
In many other languages (like JavaScript), you can throw any value. Java's strict typing catches this at compile time, but beginners often forget this rule.
Reveal each answer, then mark whether you got it right. Score 60%+ to unlock the next chapter.
'throw' is an action inside a method that actually creates and sends an exception object. 'throws' is a keyword in the method signature that declares that the method might throw that type of exception, forcing callers to handle or declare it.
The finally block almost always executes, but there are two cases where it might not: if the JVM exits via System.exit(), or if a fatal error (like StackOverflowError) occurs and the JVM crashes before the finally block runs.
Yes, but then you must have a finally block. The combination of try-finally is legal in Java. The finally block provides clean-up, and any exception from the try block is propagated up the call stack.
When a try-with-resources block throws an exception from the try body and also the close() method of a resource throws a different exception, the close() exception is 'suppressed' and attached to the primary exception. You can retrieve it using Throwable.getSuppressed().
No, assertions are disabled by default and are intended for development and testing. Enabling them in production can degrade performance and may cause unexpected program termination if an assertion fails.
Yes, using a multi-catch clause: `catch (IOException | RuntimeException e)`. This is legal as long as the two exception types are not in a parent-child relationship with each other.
You've finished Exceptions and Assertions. Continue through the 1Z0-829 study guide to build a complete picture of the exam.
Done with this chapter?