Java Tutorial 70 of 143
Basics
- Introduction
- Download and Install Java
- Download and Install IntelliJ IDEA, Eclipse
- Creating First Java Application in IntelliJ IDEA
- JDK vs JRE vs JVM
- Print output
- Taking Input
- Identifiers
- Keywords
- Variables
- Data Types
- Literals
- Wrapper Classes
- Operators
- Decision Making
- Loops and Jump Statements
- Project: Number Guessing Game
Methods
- Introduction
- Static Methods vs Instance Methods
- Access Modifiers
- Command Line Arguments
- Variable Arguments (Varargs)
Arrays
- Introduction
- One Dimensional Arrays
- Multidimensional Arrays
- Array Class
- Arrays Class
Strings
- Introduction
- String
- StringBuffer
- StringBuilder
- String Class Methods
- StringJoiner
- StringTokenizer
OOP & Interface
- Introduction
- Java Constructors
- Java Encapsulation
- Inheritance
- Java Polymorphism
- Java Abstraction
- Interfaces
- this Keyword
- super Keyword
- static Keyword
- final Keyword
- Access Modifiers
- Nested Classes
- Anonymous Inner Class
Collections
- Collection class
- Collection Interface
- List Interface
- ArrayList
- LinkedList
- Set Interface
- HashSet
- LinkedHashSet
- TreeSet
- Queue Interface
- PriorityQueue
- Deque
- ArrayDeque
- Map Interface in Java
- HashMap
- LinkedHashMap
- TreeMap
- Hashtable
- Iterator
- Comparable and Comparator
Exception Handling
- Introduction
- Java Exception Handling
- Java Try-Catch
- Java Finally Block
- Java throw and throws
- Java Custom Exceptions
- Java Checked vs Unchecked Exceptions
Multithreading & Concurrency
- Introduction
- Thread Class
- Runnable Interface
- Thread Life Cycle
- Thread Priority
- Synchronization
- Inter-Thread Communication
- Executor Framework
- Callable and Future
- Concurrent Collections
Java 8 Features
- Lambda Expressions
- Functional Interfaces
- Method References
- Stream API
- Optional Class
- Default and Static Methods in Interface
- Date and Time API
Advanced Java Concepts
- File Handling
- Serialization and Deserialization
- Reflection API
- Annotations
- Garbage Collection
- Memory Management
- JVM Architecture
- Class Loading
- Networking
- Regular Expressions
JDBC
- Introduction
- JDBC Driver
- JDBC Connection
- Types of Statements in JDBC
- Transactions
- ResultSet
- Metadata
- Connection Pooling
Web & Enterprise
- Servlets
- JSP
- Spring Framework
- Spring Boot
- Hibernate
- REST API Development
Practice Projects
- Project: Number Guessing Game
- Project: Banking System
- Project: Student Management System
- Project: Library Management System
- Project: Quiz Application
Quiz and Coding Practice
- Java Topic-wise Quiz
- Coding Practice Problems
- Java Basics Coding Practice Problems
- Java Exercises
Interview Questions
- Core Java Interview Questions and Answers
- Advanced Java Interview Questions and Answers
- Java Interview Questions
DSA & Competitive Programming
- Arrays and Strings
- Linked List
- Stack
- Queue
- Tree
- Graph
- Heap
- Hashing
- Sorting
- Searching
- Dynamic Programming
- Roadmap for DSA in Java
Java Exception Handling
Learn Java exception handling with try-catch, finally, throw, throws, custom exceptions, checked and unchecked exceptions, and practical examples.
On this page
- What Is an Exception?
- Why Is Exception Handling Needed?
- Error
- Exception
- Checked Exceptions
- Unchecked Exceptions
- ArithmeticException
- NullPointerException
- ArrayIndexOutOfBoundsException
- NumberFormatException
- IllegalArgumentException
- getMessage()
- printStackTrace()
- toString()
- Catch Specific Exceptions
- Do Not Ignore Exceptions
- Do Not Use Exceptions for Normal Control Flow
- Preserve the Original Cause
- Use Try-With-Resources
- Catching Exception Everywhere
- Losing the Original Exception
- Using throws as a Replacement for Handling Everything
- Catching the Wrong Exception Type
Java Exception Handling
Exception handling in Java is a mechanism for detecting and handling runtime problems so that a program can respond to unexpected situations without terminating abruptly.
For example, attempting to divide a number by zero causes an ArithmeticException:
int result = 10 / 0;
Instead of allowing the program to terminate because of the exception, Java provides constructs such as try, catch, finally, throw, and throws to handle exceptional situations.
What Is an Exception?
An exception is an event that occurs during program execution and disrupts the normal flow of the program.
For example:
int number = 10;
int result = number / 0;
This causes:
java.lang.ArithmeticException: / by zero
Without exception handling, the program may terminate when the exception is not handled.
Why Is Exception Handling Needed?
Exception handling helps applications:
- Prevent unexpected termination
- Handle runtime errors gracefully
- Separate error-handling code from normal program logic
- Provide meaningful error messages
- Perform cleanup operations
- Propagate errors to appropriate layers
For example, instead of:
int result = 10 / 0;
you can handle the condition:
try {
int result = 10 / 0;
}
catch (ArithmeticException e) {
System.out.println("Cannot divide by zero");
}
Output:
Cannot divide by zero
Exception Hierarchy in Java
Java exceptions are part of a class hierarchy.
The basic structure is:
Object
|
Throwable
|
+------------------+
| |
Error Exception
|
RuntimeException
Throwable is the root class for objects that can be thrown and caught.
It has two major branches:
ErrorException
Error
Error represents serious problems that applications generally should not try to recover from.
Examples include:
OutOfMemoryErrorStackOverflowErrorNoClassDefFoundError
Application code normally should not use exception handling as a general solution for these conditions.
Exception
Exception represents conditions that applications may be able to handle.
Examples include:
IOExceptionSQLExceptionClassNotFoundExceptionRuntimeException
Checked and Unchecked Exceptions
Java exceptions are commonly divided into:
- Checked exceptions
- Unchecked exceptions
Checked Exceptions
Checked exceptions are exceptions that the compiler requires you to handle or declare.
Examples include:
IOExceptionSQLExceptionFileNotFoundExceptionClassNotFoundException
Example:
import java.io.FileReader;
import java.io.IOException;
class Main {
public static void main(String[] args) {
try {
FileReader reader = new FileReader("data.txt");
}
catch (IOException e) {
System.out.println("Unable to open file");
}
}
}
The compiler requires the checked exception to be handled or declared.
Unchecked Exceptions
Unchecked exceptions are subclasses of RuntimeException.
The compiler does not require them to be explicitly caught or declared.
Examples include:
ArithmeticExceptionNullPointerExceptionArrayIndexOutOfBoundsExceptionIllegalArgumentExceptionNumberFormatException
Example:
int result = 10 / 0;
This causes an ArithmeticException.
Try-Catch
The try block contains code that may throw an exception.
The catch block handles the exception.
Syntax:
try {
// Code that may throw an exception
}
catch (ExceptionType e) {
// Handle exception
}
Example:
try {
int result = 10 / 0;
System.out.println(result);
}
catch (ArithmeticException e) {
System.out.println("Division by zero is not allowed");
}
Output:
Division by zero is not allowed
When the exception occurs, the remaining statements in the try block are skipped and the matching catch block executes.
Multiple Catch Blocks
A try statement can have multiple catch blocks.
Example:
try {
int[] numbers = {10, 20, 30};
System.out.println(numbers[5]);
}
catch (ArithmeticException e) {
System.out.println("Arithmetic error");
}
catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Array index is invalid");
}
catch (Exception e) {
System.out.println("Some other exception occurred");
}
The most specific exception should be handled before a more general exception.
For example, this ordering is correct:
catch (ArrayIndexOutOfBoundsException e) {
}
catch (Exception e) {
}
But this is invalid:
catch (Exception e) {
}
catch (ArrayIndexOutOfBoundsException e) {
}
because Exception already catches the subclass.
Finally Block
The finally block contains code that is intended to execute after the try/catch processing.
It is commonly used for cleanup operations.
Example:
try {
int result = 10 / 2;
System.out.println(result);
}
catch (ArithmeticException e) {
System.out.println("Arithmetic error");
}
finally {
System.out.println("Execution completed");
}
Output:
5
Execution completed
The finally block generally executes whether or not an exception occurs.
Example Using Finally for Resource Cleanup
Consider a resource such as a file.
FileReader reader = null;
try {
reader = new FileReader("data.txt");
}
catch (IOException e) {
System.out.println("File error");
}
finally {
if (reader != null) {
try {
reader.close();
}
catch (IOException e) {
System.out.println("Unable to close file");
}
}
}
Modern Java commonly uses try-with-resources for resources that implement AutoCloseable, which is usually simpler and safer.
Try-With-Resources
Try-with-resources automatically closes resources after the try block finishes.
Example:
import java.io.FileReader;
import java.io.IOException;
class Main {
public static void main(String[] args) {
try (FileReader reader = new FileReader("data.txt")) {
int data = reader.read();
System.out.println(data);
}
catch (IOException e) {
System.out.println("File error");
}
}
}
The FileReader is automatically closed when the try block completes.
This is preferred over manually closing many resources in a finally block.
The throw Keyword
The throw keyword is used to explicitly throw an exception.
Example:
public class Main {
public static void main(String[] args) {
int age = 15;
if (age < 18) {
throw new IllegalArgumentException("Age must be at least 18");
}
}
}
The program explicitly creates and throws an exception when the condition is invalid.
The throws Keyword
The throws keyword is used in a method declaration to indicate that the method may propagate specified exceptions to its caller.
Example:
import java.io.IOException;
class FileService {
void readFile() throws IOException {
// File operations
}
}
The caller can then handle the exception:
try {
FileService service = new FileService();
service.readFile();
}
catch (IOException e) {
System.out.println("File operation failed");
}
throw vs throws
throw |
throws |
|---|---|
| Used to explicitly throw an exception | Used to declare exceptions a method may propagate |
| Used inside a method or block | Used in a method declaration |
| Throws one exception object at a time | Can declare multiple exception types |
Example: throw new Exception() |
Example: void read() throws IOException |
Example of throw:
throw new IllegalArgumentException("Invalid value");
Example of throws:
void read() throws IOException {
}
Creating Custom Exceptions
Java allows you to create your own exception classes.
A custom exception can extend Exception for a checked exception:
class InvalidAgeException extends Exception {
public InvalidAgeException(String message) {
super(message);
}
}
Use it:
class Registration {
static void register(int age) throws InvalidAgeException {
if (age < 18) {
throw new InvalidAgeException(
"Age must be at least 18"
);
}
System.out.println("Registration successful");
}
}
Calling the method:
public class Main {
public static void main(String[] args) {
try {
Registration.register(16);
}
catch (InvalidAgeException e) {
System.out.println(e.getMessage());
}
}
}
Output:
Age must be at least 18
Custom Unchecked Exceptions
A custom unchecked exception can extend RuntimeException.
Example:
class InvalidAmountException extends RuntimeException {
public InvalidAmountException(String message) {
super(message);
}
}
Use it:
class BankAccount {
void withdraw(double amount) {
if (amount <= 0) {
throw new InvalidAmountException(
"Amount must be greater than zero"
);
}
}
}
Because the exception extends RuntimeException, callers are not required by the compiler to catch or declare it.
Common Java Exceptions
ArithmeticException
Occurs when an arithmetic operation is invalid.
int result = 10 / 0;
NullPointerException
Occurs when code attempts to use a null reference where an object is required.
String name = null;
System.out.println(name.length());
ArrayIndexOutOfBoundsException
Occurs when an invalid index is used with an array.
int[] numbers = {10, 20, 30};
System.out.println(numbers[5]);
NumberFormatException
Occurs when a string cannot be converted to the requested numeric type.
int number = Integer.parseInt("abc");
IllegalArgumentException
Indicates that a method has received an inappropriate argument.
throw new IllegalArgumentException("Invalid age");
Exception Propagation
If an exception is not handled in the current method, it can propagate up the call stack to the calling method.
Example:
class Main {
static void method3() {
int result = 10 / 0;
}
static void method2() {
method3();
}
static void method1() {
method2();
}
public static void main(String[] args) {
try {
method1();
}
catch (ArithmeticException e) {
System.out.println("Exception handled in main");
}
}
}
The exception occurs in method3() but is eventually handled in main().
The propagation path is:
main()
|
method1()
|
method2()
|
method3()
|
ArithmeticException
Nested Try-Catch
A try block can be placed inside another try block.
Example:
try {
try {
int result = 10 / 0;
}
catch (ArithmeticException e) {
System.out.println("Inner exception handled");
}
}
catch (Exception e) {
System.out.println("Outer exception handled");
}
Nested exception handling should be used only when it provides a clear separation of responsibilities.
Exception Methods
The Throwable class provides useful methods for understanding exceptions.
getMessage()
Returns the exception message.
catch (Exception e) {
System.out.println(e.getMessage());
}
printStackTrace()
Prints the exception and its stack trace.
catch (Exception e) {
e.printStackTrace();
}
toString()
Returns a string representation containing the exception type and message.
catch (Exception e) {
System.out.println(e.toString());
}
Exception Chaining
Exception chaining allows one exception to preserve another exception as its cause.
Example:
try {
// Some operation
}
catch (IOException e) {
throw new RuntimeException(
"Unable to process file",
e
);
}
The original IOException is preserved as the cause of the new exception.
This is useful when translating low-level exceptions into exceptions that make more sense at a higher application layer.
Multi-Catch
Java allows multiple exception types to be handled by a single catch block.
Example:
try {
// Code that may throw different exceptions
}
catch (IOException | NumberFormatException e) {
System.out.println("Operation failed");
}
This can reduce duplicate exception-handling code when the handling logic is the same.
Exception Handling Best Practices
Catch Specific Exceptions
Prefer:
catch (IOException e) {
}
over unnecessarily broad handling:
catch (Exception e) {
}
A specific exception communicates what the code expects and allows more appropriate handling.
Do Not Ignore Exceptions
Avoid empty catch blocks:
catch (Exception e) {
}
Ignoring exceptions can hide application problems.
At minimum, handle, log, or propagate the exception appropriately.
Do Not Use Exceptions for Normal Control Flow
Exceptions should generally represent exceptional situations rather than expected everyday branching.
Instead of relying on an exception to determine whether an operation normally succeeds, use appropriate validation or control flow.
Preserve the Original Cause
When wrapping an exception, preserve its cause:
throw new RuntimeException("Operation failed", e);
This makes debugging easier.
Use Try-With-Resources
For resources such as files, streams, and database-related objects that implement AutoCloseable, prefer try-with-resources:
try (FileReader reader = new FileReader("data.txt")) {
// Use resource
}
This automatically manages resource cleanup.
Checked vs Unchecked Exceptions
| Checked Exceptions | Unchecked Exceptions |
|---|---|
Usually subclasses of Exception excluding RuntimeException |
Subclasses of RuntimeException |
| Checked by the compiler | Not required to be caught or declared |
| Must be caught or declared | Can propagate without explicit declaration |
| Often represent conditions an application may reasonably handle | Often indicate programming errors or invalid runtime conditions |
Example: IOException |
Example: NullPointerException |
The distinction is primarily about Java's compile-time checking rules.
finally vs Try-With-Resources
Both can be used for cleanup, but try-with-resources is generally preferred for objects that implement AutoCloseable.
Traditional approach:
FileReader reader = null;
try {
reader = new FileReader("data.txt");
}
finally {
if (reader != null) {
reader.close();
}
}
Try-with-resources:
try (FileReader reader = new FileReader("data.txt")) {
// Use reader
}
The second approach is shorter and automatically handles resource closure.
Common Mistakes
Catching Exception Everywhere
Avoid using broad exception handling without a reason:
try {
// code
}
catch (Exception e) {
System.out.println("Error");
}
It can make it difficult to understand what actually went wrong.
Losing the Original Exception
Avoid replacing an exception without preserving its cause:
catch (IOException e) {
throw new RuntimeException("Failed");
}
Prefer:
catch (IOException e) {
throw new RuntimeException("Failed", e);
}
Using throws as a Replacement for Handling Everything
Declaring an exception with throws does not handle it. It passes responsibility to the caller.
void readFile() throws IOException {
}
The caller still needs to decide how the exception should be handled or propagated.
Catching the Wrong Exception Type
The exception type in a catch block must match the thrown exception or be one of its supertypes.
For example:
try {
int result = 10 / 0;
}
catch (IOException e) {
// Does not catch ArithmeticException
}
Key Points to Remember
- An exception is an event that disrupts the normal execution of a program.
- Java provides
try,catch,finally,throw, andthrowsfor exception handling. - Checked exceptions are subject to compile-time checking.
- Unchecked exceptions are subclasses of
RuntimeException. throwexplicitly throws an exception.throwsdeclares exceptions that a method may propagate.- Multiple
catchblocks can handle different exception types. finallyis commonly used for cleanup.- Try-with-resources automatically closes
AutoCloseableresources. - Custom exceptions can be created by extending
ExceptionorRuntimeException. - Exceptions can propagate up the call stack.
- Exception chaining preserves the original cause.
- Specific exception handling is generally preferable to unnecessarily broad catches.
Conclusion
Exception handling in Java provides a structured way to deal with errors and unexpected runtime conditions. Using try, catch, finally, throw, and throws, developers can control how exceptional situations are detected, handled, and propagated.
For resource management, try-with-resources provides a convenient way to automatically close resources. For application-specific conditions, custom exceptions can make error handling clearer and more meaningful.
Effective exception handling should make failures easier to understand and recover from without hiding important problems in the application.
Related
-
Java throw and throws
Learn the difference between Java throw and throws, how to explicitly throw exceptions, declare exceptions in methods, and handle checked and unchecked exceptions.
-
Java Finally Block
Learn how the Java finally block works, when it executes, how it works with try-catch, resource cleanup, return statements, and try-with-resources.
-
Java Try-Catch
Learn how to handle exceptions in Java using try-catch blocks, multiple catch blocks, exception types, nested try-catch, and practical examples.
-
Java Checked vs Unchecked Exceptions
Learn the difference between checked and unchecked exceptions in Java, including compiler checking, exception handling, examples, use cases, and best practices.