Exception Handling and Assertions

Java 12 min min read Updated: Mar 31, 2026 Intermediate
Exception Handling and Assertions
Intermediate Topic 4 of 14

Exception Handling and Assertions

In Java, programs do not always run in perfect conditions. A user may enter invalid input, a file may not exist, a network connection may fail, or a database may become unavailable. If such situations are not handled properly, the program may terminate unexpectedly.

Java provides a strong mechanism called exception handling to deal with runtime problems gracefully. Along with that, Java also provides assertions, which are used to verify assumptions during development and debugging.

Key Concept: Exception handling is used to manage abnormal conditions during program execution, while assertions are used to validate assumptions and catch logic errors during development.

What is an Exception?

An exception is an unwanted or abnormal event that occurs during program execution and interrupts the normal flow of the program.

Examples of runtime problems:

  • dividing by zero
  • accessing an invalid array index
  • opening a missing file
  • converting invalid text into a number
  • calling a method on a null reference

Example Without Exception Handling

java public class Main { public static void main(String[] args) { int a = 10; int b = 0; System.out.println(a / b); System.out.println("Program ends"); } }

This program throws an exception and stops before printing "Program ends".

Why Exception Handling is Important

  • prevents sudden program termination
  • helps handle errors gracefully
  • improves application reliability
  • makes debugging easier
  • provides meaningful messages to users and developers

Exception Hierarchy in Java

Java exceptions are organized in a hierarchy. The root class is:

text java.lang.Throwable

Under Throwable, there are two major branches:

  • Error
  • Exception

1. Error

Errors represent serious problems that generally cannot be handled by application code.

Examples:

  • OutOfMemoryError
  • StackOverflowError

Errors are usually related to JVM or system-level failures.

2. Exception

Exceptions represent conditions that an application can often handle.

Exceptions are mainly divided into:

  • Checked exceptions
  • Unchecked exceptions

Checked Exceptions

Checked exceptions are checked by the compiler. The programmer must either handle them using try-catch or declare them using throws.

Examples:

  • IOException
  • FileNotFoundException
  • SQLException

Example

java import java.io.FileReader; public class Main { public static void main(String[] args) throws Exception { FileReader fr = new FileReader("data.txt"); } }

Since file operations may fail, Java forces the programmer to handle or declare the exception.

Unchecked Exceptions

Unchecked exceptions are not checked by the compiler. They usually occur because of programming mistakes.

Examples:

  • ArithmeticException
  • NullPointerException
  • ArrayIndexOutOfBoundsException
  • NumberFormatException

Example

java public class Main { public static void main(String[] args) { String s = null; System.out.println(s.length()); } }

This causes NullPointerException.

Difference Between Checked and Unchecked Exceptions

Point Checked Exception Unchecked Exception
Compiler check Yes No
Handling required? Yes Not mandatory
Cause External or predictable conditions Programming mistakes or invalid logic
Examples IOException, SQLException ArithmeticException, NullPointerException

Exception Handling Keywords

Java exception handling mainly uses these keywords:

  • try
  • catch
  • finally
  • throw
  • throws

try Block

The try block contains code that may produce an exception.

catch Block

The catch block handles the exception if it occurs.

Basic try-catch Example

java public class Main { public static void main(String[] args) { try { int a = 10; int b = 0; System.out.println(a / b); } catch (ArithmeticException e) { System.out.println("Cannot divide by zero"); } System.out.println("Program continues"); } }

Output

text Cannot divide by zero Program continues

Here, the exception is caught, and the program continues normally.

Multiple catch Blocks

One try block can have multiple catch blocks to handle different exceptions.

java public class Main { public static void main(String[] args) { try { String s = null; System.out.println(s.length()); } catch (ArithmeticException e) { System.out.println("Arithmetic error"); } catch (NullPointerException e) { System.out.println("Null value found"); } } }

The appropriate catch block executes based on the actual exception type.

finally Block

The finally block executes whether an exception occurs or not. It is commonly used for cleanup operations like closing files, database connections, or releasing resources.

Example

java public class Main { public static void main(String[] args) { try { System.out.println("Inside try"); } catch (Exception e) { System.out.println("Inside catch"); } finally { System.out.println("Inside finally"); } } }

Output

text Inside try Inside finally

finally with Exception Example

java public class Main { public static void main(String[] args) { try { int x = 10 / 0; } catch (ArithmeticException e) { System.out.println("Handled exception"); } finally { System.out.println("Always executes"); } } }

throw Keyword

The throw keyword is used to explicitly create and throw an exception.

Example

java public class Main { public static void main(String[] args) { int age = 15; if (age < 18) { throw new ArithmeticException("Not eligible"); } } }

Here, the exception is thrown manually.

throws Keyword

The throws keyword is used in method declaration to indicate that the method may throw an exception.

Example

java import java.io.FileReader; import java.io.IOException; class Demo { void readFile() throws IOException { FileReader fr = new FileReader("data.txt"); } }

This tells the caller that readFile() may throw IOException.

throw vs throws

Point throw throws
Purpose Used to explicitly throw exception Used to declare possible exceptions
Used in Method body Method declaration
Example throw new Exception(); void show() throws Exception

Exception Propagation

When a method throws an exception and does not handle it, the exception moves upward to the caller. This is called exception propagation.

java class Demo { void method1() { method2(); } void method2() { int x = 10 / 0; } } public class Main { public static void main(String[] args) { Demo d = new Demo(); d.method1(); } }

Since method2() does not handle the exception, it propagates upward.

Custom Exception

Java allows programmers to create their own exceptions by extending the Exception class or RuntimeException.

Example

java class InvalidAgeException extends Exception { InvalidAgeException(String message) { super(message); } }

Using Custom Exception

java public class Main { static void checkAge(int age) throws InvalidAgeException { if (age < 18) { throw new InvalidAgeException("Age must be 18 or above"); } } public static void main(String[] args) { try { checkAge(15); } catch (InvalidAgeException e) { System.out.println(e.getMessage()); } } }

try-with-resources

Java provides try-with-resources for automatic resource management. It is commonly used with files, streams, sockets, and database resources.

Example

java import java.io.BufferedReader; import java.io.FileReader; public class Main { public static void main(String[] args) throws Exception { try (BufferedReader br = new BufferedReader(new FileReader("data.txt"))) { System.out.println(br.readLine()); } } }

Here, the resource is automatically closed after use.

What is Assertion in Java?

An assertion is a statement used to test assumptions in a program. Assertions are mainly used during development and debugging to verify that the program is behaving as expected.

If the assertion condition becomes false, Java throws an AssertionError.

Why Assertions are Used

  • to validate assumptions in code
  • to detect logic errors early
  • to support debugging and testing
  • to catch impossible states during development

Assertions are not meant for handling user input or normal runtime validation.

Assertion Syntax

Simple Form

java assert condition;

With Message

java assert condition : "Error message";

Example of Assertion

java public class Main { public static void main(String[] args) { int age = -5; assert age >= 0 : "Age cannot be negative"; System.out.println("Valid age"); } }

If assertions are enabled and the condition is false, Java throws:

text java.lang.AssertionError: Age cannot be negative

How to Enable Assertions

Assertions are disabled by default. They must be enabled using the JVM option:

bash java -ea Main

Here, -ea means “enable assertions”.

When to Use Assertions

  • for internal assumptions in code
  • for debugging
  • for verifying conditions that should always be true
  • for testing invariants and logic flow

When Not to Use Assertions

  • not for user input validation
  • not for public API argument checking in production code
  • not for handling recoverable runtime problems

Wrong Use Example

java assert username != null : "Username cannot be null";

This is not ideal for public runtime validation, because assertions may be disabled in production.

Exception Handling vs Assertion

Point Exception Handling Assertion
Purpose Handle runtime problems gracefully Check assumptions during development
Used for Expected abnormal situations Internal logic verification
Enabled always? Yes No, must be enabled manually
Error type Exception AssertionError

Real-World Example

Consider a banking system:

  • If a file is missing → handle exception
  • If internal code assumes account balance should never be negative after a specific calculation → use assertion during testing

Example

java class BankAccount { double balance = 5000; void withdraw(double amount) { balance -= amount; assert balance >= 0 : "Balance should not go negative unexpectedly"; } }

This is useful during development to catch logic issues.

Common Mistakes

  • Using == conditions incorrectly in exception logic
  • Using generic Exception everywhere without specific handling
  • Ignoring checked exceptions
  • Thinking finally executes only when exception occurs
  • Using assertions for user input validation

Best Practices

  • Catch specific exceptions instead of broad generic ones when possible
  • Use finally or try-with-resources for cleanup
  • Create custom exceptions for business-specific errors
  • Use assertions only for internal assumptions during development
  • Provide meaningful exception messages

Interview-Oriented Points

  • Exception is an abnormal event that disrupts program flow
  • Checked exceptions are compiler-checked, unchecked exceptions are not
  • try, catch, finally, throw, and throws are exception-handling keywords
  • finally executes whether exception occurs or not
  • throw is used to explicitly throw exception, throws declares exceptions
  • Assertions are used to verify assumptions in code
  • Assertions are disabled by default and enabled using -ea

Conclusion

Exception handling is a critical part of Java programming because real-world programs must deal with errors in a controlled and meaningful way. It helps applications remain stable and user-friendly even when unexpected situations occur.

Assertions, on the other hand, are mainly for development-time checking. They help detect hidden logic errors and invalid assumptions early. Together, exception handling and assertions make Java programs stronger, safer, and easier to debug.

Quick Summary: Exception handling manages runtime problems gracefully using try-catch-finally and related keywords, while assertions are development-time checks used to validate assumptions and catch logic errors early.

Get Newsletter

Subscibe to our newsletter and we will notify you about the newest updates on Edugators