Chapter 14: Errors & Exceptions
Introduction to Errors
No matter how smart we are, errors are our constant companions. With practice, we keep getting better at finding & correcting them.
There are three types of errors in Java:
1. Syntax Errors
When compiler finds something wrong with our program, it throws a syntax error.
int a = 9 // No semicolon - syntax error!d = 4; // Variable not declared - syntax error!
2. Logical Errors
A logical error or a bug occurs when a program compiles and runs but does the wrong thing.
3. Runtime Errors
Java may sometimes encounter an error while the program is running. These are also called exceptions!
Who Encounters What?
| Error Type | Encountered By | When | Example |
|---|---|---|---|
| Syntax Errors | Programmer | Compile time | Missing semicolon, undeclared variables |
| Logical Errors | Programmer | During testing | Wrong algorithm, incorrect calculations |
| Runtime Errors | Users | Runtime | Invalid input, resource constraints |
Runtime Error Example
These are encountered due to circumstances like bad input and/or resource constraints.
Example: User supplies "5" + "8" to a program which adds 2 numbers
The program expects integers but receives strings, causing a runtime exception.
Exceptions in Java
An Exception is an event that occurs when a program is executed disrupting the normal flow of instructions.
1. Checked Exceptions
Compile time exceptions (Handled by Compiler)
2. Unchecked Exceptions
Runtime exceptions
Commonly Occurring Exceptions in Java
1. NullPointerException
Occurs when trying to access methods or fields of a null object.
String str = null;
int length = str.length(); // NullPointerException
2. ArithmeticException
Occurs during arithmetic operations like division by zero.
int result = 10 / 0; // ArithmeticException
3. ArrayIndexOutOfBoundsException
Occurs when accessing array with invalid index.
int[] arr = {1, 2, 3};
int value = arr[5]; // ArrayIndexOutOfBoundsException
4. IllegalArgumentException
Occurs when a method receives inappropriate arguments.
Thread.sleep(-1000); // IllegalArgumentException
5. NumberFormatException
Occurs when trying to convert invalid string to number.
int num = Integer.parseInt("abc"); // NumberFormatException
Try-Catch Block in Java
In Java, exceptions are managed using try-catch blocks.
Basic Syntax:
try {
// Code to try
} catch (Exception e) {
// Code if exception occurs
}
public class BasicTryCatch {
public static void main(String[] args) {
try {
int a = 10;
int b = 0;
int result = a / b; // This will cause ArithmeticException
System.out.println("Result: " + result);
} catch (ArithmeticException e) {
System.out.println("Error: Cannot divide by zero!");
System.out.println("Exception message: " + e.getMessage());
}
System.out.println("Program continues after exception handling");
// Another example with array
try {
int[] numbers = {1, 2, 3, 4, 5};
System.out.println("Element at index 10: " + numbers[10]);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Error: Array index out of bounds!");
System.out.println("Exception: " + e.toString());
}
// Example with null pointer
try {
String text = null;
int length = text.length();
} catch (NullPointerException e) {
System.out.println("Error: Null pointer exception occurred!");
e.printStackTrace(); // Print full stack trace
}
}
}
Benefits of Try-Catch
Handling Specific Exceptions
In Java, we can handle specific exceptions by using multiple catch blocks.
import java.io.*;
import java.util.Scanner;
public class MultipleExceptions {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
try {
System.out.print("Enter first number: ");
int num1 = Integer.parseInt(scanner.nextLine());
System.out.print("Enter second number: ");
int num2 = Integer.parseInt(scanner.nextLine());
int result = num1 / num2;
System.out.println("Result: " + result);
// Array access example
int[] arr = {1, 2, 3};
System.out.println("Array element: " + arr[result]);
} catch (NumberFormatException e) {
System.out.println("Error: Please enter valid integers!");
System.out.println("Details: " + e.getMessage());
} catch (ArithmeticException e) {
System.out.println("Error: Division by zero is not allowed!");
System.out.println("Details: " + e.getMessage());
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Error: Array index out of bounds!");
System.out.println("Details: " + e.getMessage());
} catch (Exception e) {
// Generic catch block for any other exceptions
System.out.println("An unexpected error occurred: " + e.getMessage());
e.printStackTrace();
}
System.out.println("Program execution completed.");
scanner.close();
}
}
Rules for Multiple Catch Blocks
public class CatchOrderExample {
public static void main(String[] args) {
// CORRECT ORDER - Specific to General
try {
int[] arr = new int[5];
arr[10] = 50; // ArrayIndexOutOfBoundsException
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Array index error: " + e.getMessage());
} catch (RuntimeException e) {
System.out.println("Runtime error: " + e.getMessage());
} catch (Exception e) {
System.out.println("General error: " + e.getMessage());
}
// INCORRECT ORDER - Would cause compilation error
/*
try {
// some code
} catch (Exception e) { // Too general - should be last
System.out.println("General error");
} catch (ArithmeticException e) { // Unreachable code - compilation error
System.out.println("Arithmetic error");
}
*/
}
}
Exception Class Hierarchy
All exceptions in Java inherit from the Throwable class.
Exception Class Hierarchy
Important Exception Methods
| Method | Description | Example |
|---|---|---|
getMessage() |
Returns the detail message of the exception | e.getMessage() |
toString() |
Returns exception class name and message | e.toString() |
printStackTrace() |
Prints the stack trace to standard error | e.printStackTrace() |
getStackTrace() |
Returns array of stack trace elements | e.getStackTrace() |
getCause() |
Returns the cause of the exception | e.getCause() |
public class ExceptionMethodsExample {
public static void main(String[] args) {
try {
// Intentionally cause an exception
int result = 10 / 0;
} catch (ArithmeticException e) {
System.out.println("=== Exception Information ===");
// getMessage() - Returns the detail message
System.out.println("Message: " + e.getMessage());
// toString() - Returns class name and message
System.out.println("ToString: " + e.toString());
// getClass() - Returns the exception class
System.out.println("Class: " + e.getClass().getName());
// printStackTrace() - Prints full stack trace
System.out.println("\nStack Trace:");
e.printStackTrace();
// getStackTrace() - Returns stack trace as array
System.out.println("\nStack Trace Elements:");
StackTraceElement[] stackTrace = e.getStackTrace();
for (StackTraceElement element : stackTrace) {
System.out.println(" " + element.toString());
}
}
// Example with nested method calls
try {
methodA();
} catch (Exception e) {
System.out.println("\n=== Nested Method Exception ===");
System.out.println("Exception in nested method: " + e.getMessage());
e.printStackTrace();
}
}
static void methodA() {
methodB();
}
static void methodB() {
methodC();
}
static void methodC() {
// This will show the call stack
String str = null;
int length = str.length(); // NullPointerException
}
}
Throw and Throws Keywords
The throw and throws keywords are used for exception handling in Java.
throw Keyword
throw new ArithmeticException("Division by zero");
throws Keyword
public void method() throws IOException, SQLException
public class ThrowExample {
// Method that throws an exception explicitly
public static void validateAge(int age) {
if (age < 18) {
throw new IllegalArgumentException("Age must be 18 or older. Provided: " + age);
}
System.out.println("Age is valid: " + age);
}
// Method that throws custom exception
public static void divide(int a, int b) {
if (b == 0) {
throw new ArithmeticException("Cannot divide by zero! Divisor: " + b);
}
int result = a / b;
System.out.println("Division result: " + result);
}
// Method that validates array index
public static void accessArray(int[] arr, int index) {
if (index < 0 || index >= arr.length) {
throw new ArrayIndexOutOfBoundsException(
"Invalid index: " + index + ". Array length: " + arr.length);
}
System.out.println("Array element at index " + index + ": " + arr[index]);
}
public static void main(String[] args) {
// Example 1: Age validation
try {
validateAge(25); // Valid age
validateAge(15); // Invalid age - will throw exception
} catch (IllegalArgumentException e) {
System.out.println("Age validation error: " + e.getMessage());
}
// Example 2: Division
try {
divide(10, 2); // Valid division
divide(10, 0); // Invalid division - will throw exception
} catch (ArithmeticException e) {
System.out.println("Division error: " + e.getMessage());
}
// Example 3: Array access
try {
int[] numbers = {1, 2, 3, 4, 5};
accessArray(numbers, 2); // Valid index
accessArray(numbers, 10); // Invalid index - will throw exception
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Array access error: " + e.getMessage());
}
}
}
import java.io.*;
public class ThrowsExample {
// Method that declares it might throw IOException
public static void readFile(String filename) throws IOException {
FileReader file = new FileReader(filename);
BufferedReader reader = new BufferedReader(file);
String line = reader.readLine();
System.out.println("First line: " + line);
reader.close();
}
// Method that declares multiple exceptions
public static void processData(String data) throws NumberFormatException, IllegalArgumentException {
if (data == null || data.trim().isEmpty()) {
throw new IllegalArgumentException("Data cannot be null or empty");
}
int number = Integer.parseInt(data); // May throw NumberFormatException
System.out.println("Processed number: " + number);
}
// Method that calls other methods with throws
public static void performOperations() throws IOException, NumberFormatException {
readFile("data.txt"); // Must handle or declare IOException
processData("123"); // Must handle or declare NumberFormatException
}
public static void main(String[] args) {
// Handling IOException from readFile
try {
readFile("example.txt");
} catch (IOException e) {
System.out.println("File reading error: " + e.getMessage());
}
// Handling multiple exceptions from processData
try {
processData("abc"); // Will throw NumberFormatException
} catch (NumberFormatException e) {
System.out.println("Number format error: " + e.getMessage());
} catch (IllegalArgumentException e) {
System.out.println("Argument error: " + e.getMessage());
}
// Handling exceptions from performOperations
try {
performOperations();
} catch (IOException e) {
System.out.println("IO error in operations: " + e.getMessage());
} catch (NumberFormatException e) {
System.out.println("Number format error in operations: " + e.getMessage());
}
}
}
Creating Custom Exceptions
// Custom exception class
class InsufficientBalanceException extends Exception {
public InsufficientBalanceException(String message) {
super(message);
}
}
class BankAccount {
private double balance;
public BankAccount(double initialBalance) {
this.balance = initialBalance;
}
public void withdraw(double amount) throws InsufficientBalanceException {
if (amount > balance) {
throw new InsufficientBalanceException(
"Insufficient balance. Available: " + balance + ", Requested: " + amount);
}
balance -= amount;
System.out.println("Withdrawal successful. Remaining balance: " + balance);
}
public double getBalance() {
return balance;
}
}
public class CustomExceptionExample {
public static void main(String[] args) {
BankAccount account = new BankAccount(1000.0);
try {
account.withdraw(500); // Valid withdrawal
account.withdraw(600); // Invalid - insufficient balance
} catch (InsufficientBalanceException e) {
System.out.println("Transaction failed: " + e.getMessage());
}
}
}
Finally Block
The finally block contains code that is always executed, whether an exception occurs or not.
It's typically used for cleanup operations like closing files, database connections, etc.
Finally Block Syntax
try {
// Code that may throw exception
} catch (Exception e) {
// Exception handling code
} finally {
// Code that always executes
}
import java.io.*;
public class FinallyExample {
public static void demonstrateFinally() {
FileReader file = null;
try {
System.out.println("Opening file...");
file = new FileReader("example.txt");
// Simulate some file operations
int data = file.read();
System.out.println("File data read successfully");
} catch (IOException e) {
System.out.println("Error reading file: " + e.getMessage());
} finally {
// This block always executes
System.out.println("Finally block executing...");
if (file != null) {
try {
file.close();
System.out.println("File closed successfully");
} catch (IOException e) {
System.out.println("Error closing file: " + e.getMessage());
}
}
}
}
public static int demonstrateFinallyWithReturn() {
try {
System.out.println("In try block");
return 1;
} catch (Exception e) {
System.out.println("In catch block");
return 2;
} finally {
System.out.println("In finally block - this always executes");
// Note: return in finally block would override try/catch return
}
}
public static void demonstrateFinallyWithoutCatch() {
try {
System.out.println("Try block without catch");
int result = 10 / 2; // No exception
System.out.println("Result: " + result);
} finally {
System.out.println("Finally executes even without catch block");
}
}
public static void main(String[] args) {
System.out.println("=== Example 1: Finally with Exception ===");
demonstrateFinally();
System.out.println("\n=== Example 2: Finally with Return ===");
int result = demonstrateFinallyWithReturn();
System.out.println("Returned value: " + result);
System.out.println("\n=== Example 3: Finally without Catch ===");
demonstrateFinallyWithoutCatch();
System.out.println("\n=== Example 4: Multiple Operations ===");
performMultipleOperations();
}
public static void performMultipleOperations() {
int[] numbers = {1, 2, 3, 4, 5};
try {
System.out.println("Starting operations...");
// Operation 1: Array access
System.out.println("Element at index 2: " + numbers[2]);
// Operation 2: Division
int result = 10 / 2;
System.out.println("Division result: " + result);
// Operation 3: Potential exception
System.out.println("Element at index 10: " + numbers[10]); // Exception here
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Array error: " + e.getMessage());
} catch (ArithmeticException e) {
System.out.println("Math error: " + e.getMessage());
} finally {
System.out.println("Cleanup operations completed");
System.out.println("Resources released");
}
System.out.println("Method execution completed");
}
}
Important Rules for Finally Block
Try-with-Resources (Java 7+)
A more elegant way to handle resources that implement AutoCloseable:
import java.io.*;
public class TryWithResources {
public static void readFileWithResources(String filename) {
// Resources declared in try() are automatically closed
try (FileReader file = new FileReader(filename);
BufferedReader reader = new BufferedReader(file)) {
String line = reader.readLine();
System.out.println("File content: " + line);
} catch (IOException e) {
System.out.println("Error reading file: " + e.getMessage());
}
// No need for finally block - resources auto-closed
}
public static void main(String[] args) {
readFileWithResources("example.txt");
}
}
Practice Set
Chapter 14 - Practice Set
1. Syntax Error Demo
Write a Java program that demonstrates syntax error.
2. Runtime Error Demo
Write a Java program that demonstrates runtime error (exception).
3. Exception Handling
Write a program that allows you to keep accessing an array until a valid index is given by the user.
4. Multiple Catch Blocks
Modify program 3 to include IllegalArgumentException as well as any other exception that occurs during runtime.
5. Nested Try-Catch
Write a program that demonstrates nested try-catch blocks.
6. Custom Exception
Create a custom exception class and demonstrate its usage.