Declaring Checked Exceptions

Introduction

Declaring exceptions means telling the compiler that a method might throw a checked exception. Use the throws keyword.


Why Declare?

For checked exceptions, you must either:

  1. Handle with try-catch, OR
  2. Declare with throws

If you don’t handle it, declare it so caller knows to handle.


throws Keyword

Syntax:

accessModifier returnType methodName() throws ExceptionType {
    // Method body
}

Simple Example

import java.io.*;

class FileHandler {
    // Declaring that this method may throw IOException
    void readFile(String filename) throws IOException {
        FileReader fr = new FileReader(filename);  // May throw FileNotFoundException
        BufferedReader br = new BufferedReader(fr);
        String line = br.readLine();  // May throw IOException
        System.out.println(line);
        br.close();
    }
}

public class Main {
    public static void main(String[] args) {
        FileHandler handler = new FileHandler();

        // Must handle declared exception
        try {
            handler.readFile("test.txt");
        } catch (IOException e) {
            System.out.println("Error: " + e.getMessage());
        }
    }
}

Without Declaration (Error)

import java.io.*;

// ✗ Won't compile - must handle or declare
void readFile(String filename) {
    FileReader fr = new FileReader(filename);  // Compile error!
    // Error: Unhandled exception java.io.FileNotFoundException
}

With Declaration (Correct)

import java.io.*;

// ✓ Compiles - exception declared
void readFile(String filename) throws FileNotFoundException {
    FileReader fr = new FileReader(filename);
    // Caller must handle this exception
}

Multiple Exceptions

Declare multiple exceptions separated by comma.

import java.io.*;
import java.sql.*;

class DataHandler {
    // Method may throw multiple exceptions
    void processData(String filename) throws IOException, SQLException {
        // File operations - may throw IOException
        FileReader fr = new FileReader(filename);

        // Database operations - may throw SQLException
        // Connection conn = DriverManager.getConnection(...);
    }
}

public class Main {
    public static void main(String[] args) {
        DataHandler handler = new DataHandler();

        // Handle both exceptions
        try {
            handler.processData("data.txt");
        } catch (IOException e) {
            System.out.println("File error: " + e.getMessage());
        } catch (SQLException e) {
            System.out.println("Database error: " + e.getMessage());
        }
    }
}

Exception Propagation

When method declares exception, caller must handle or declare again.

import java.io.*;

class Demo {
    // Level 3 - throws exception
    void method3() throws IOException {
        FileReader fr = new FileReader("test.txt");
    }

    // Level 2 - declares same exception (propagates)
    void method2() throws IOException {
        method3();  // Declares exception, so we must too
    }

    // Level 1 - finally handles
    void method1() {
        try {
            method2();
        } catch (IOException e) {
            System.out.println("Exception handled: " + e.getMessage());
        }
    }
}

public class Main {
    public static void main(String[] args) {
        Demo d = new Demo();
        d.method1();  // No exception to handle here
    }
}

Declaring in main()

Can declare in main() - JVM will handle.

import java.io.*;

public class Main {
    // Declaring in main - JVM handles exception
    public static void main(String[] args) throws IOException {
        FileReader fr = new FileReader("test.txt");
        BufferedReader br = new BufferedReader(fr);
        System.out.println(br.readLine());
        br.close();
    }
}

Note: If exception occurs, program will terminate with error message.


Parent Exception

Can declare parent exception instead of specific.

import java.io.*;

// Specific exception
void method1() throws FileNotFoundException {
    FileReader fr = new FileReader("test.txt");
}

// Parent exception (also valid)
void method2() throws IOException {
    FileReader fr = new FileReader("test.txt");  // FileNotFoundException is subclass of IOException
}

// Most general
void method3() throws Exception {
    FileReader fr = new FileReader("test.txt");  // Any exception
}

Best Practice: Declare specific exceptions for clarity.


Complete Example: Student Database

import java.io.*;
import java.sql.*;

class StudentDatabase {
    // Method declares multiple exceptions
    void loadFromFile(String filename) throws IOException {
        FileReader fr = new FileReader(filename);
        BufferedReader br = new BufferedReader(fr);

        String line;
        while ((line = br.readLine()) != null) {
            System.out.println(line);
        }

        br.close();
    }

    // Method declares SQL exception
    void saveToDatabase(String data) throws SQLException {
        // Simulating database operation
        if (data == null) {
            throw new SQLException("Cannot save null data");
        }
        System.out.println("Saved to database: " + data);
    }

    // Method declares both exceptions
    void importData(String filename) throws IOException, SQLException {
        loadFromFile(filename);      // May throw IOException
        saveToDatabase("test data"); // May throw SQLException
    }
}

public class Main {
    public static void main(String[] args) {
        StudentDatabase db = new StudentDatabase();

        // Handle all declared exceptions
        try {
            db.loadFromFile("students.txt");
            db.saveToDatabase("New Student");
            db.importData("import.txt");
        } catch (FileNotFoundException e) {
            System.out.println("File not found: " + e.getMessage());
        } catch (IOException e) {
            System.out.println("I/O error: " + e.getMessage());
        } catch (SQLException e) {
            System.out.println("Database error: " + e.getMessage());
        }
    }
}

Overriding Methods

Rules when overriding methods that declare exceptions:

Rule 1: Can declare same exception

class Parent {
    void method() throws IOException { }
}

class Child extends Parent {
    @Override
    void method() throws IOException { }  // ✓ OK - same
}

Rule 2: Can declare subclass exception

class Parent {
    void method() throws IOException { }
}

class Child extends Parent {
    @Override
    void method() throws FileNotFoundException { }  // ✓ OK - subclass
}

Rule 3: Cannot declare broader exception

class Parent {
    void method() throws IOException { }
}

class Child extends Parent {
    @Override
    void method() throws Exception { }  // ✗ Error - broader
}

Rule 4: Can declare no exception

class Parent {
    void method() throws IOException { }
}

class Child extends Parent {
    @Override
    void method() { }  // ✓ OK - no exception
}

Unchecked Exceptions

Don’t need to declare unchecked exceptions (but can).

// Unchecked - no need to declare
void divide(int a, int b) {
    int result = a / b;  // May throw ArithmeticException
    System.out.println(result);
}

// Can declare if you want (but not required)
void divide2(int a, int b) throws ArithmeticException {
    int result = a / b;
    System.out.println(result);
}

Best Practice: Don’t declare unchecked exceptions (unnecessary).


Real-World Example: File Operations

import java.io.*;

class FileManager {
    // Read file - declares IOException
    String readFile(String filename) throws IOException {
        BufferedReader br = new BufferedReader(new FileReader(filename));
        StringBuilder content = new StringBuilder();
        String line;

        while ((line = br.readLine()) != null) {
            content.append(line).append("\n");
        }

        br.close();
        return content.toString();
    }

    // Write file - declares IOException
    void writeFile(String filename, String content) throws IOException {
        BufferedWriter bw = new BufferedWriter(new FileWriter(filename));
        bw.write(content);
        bw.close();
    }

    // Copy file - declares IOException
    void copyFile(String source, String dest) throws IOException {
        String content = readFile(source);  // May throw
        writeFile(dest, content);           // May throw
        System.out.println("File copied successfully");
    }
}

public class Main {
    public static void main(String[] args) {
        FileManager fm = new FileManager();

        try {
            String content = fm.readFile("input.txt");
            System.out.println("File content:\n" + content);

            fm.writeFile("output.txt", "Hello World");
            System.out.println("File written");

            fm.copyFile("source.txt", "destination.txt");
        } catch (FileNotFoundException e) {
            System.out.println("File not found: " + e.getMessage());
        } catch (IOException e) {
            System.out.println("I/O error: " + e.getMessage());
        }
    }
}

throws vs throw

Featurethrowsthrow
PurposeDeclare exceptionThrow exception
UsageMethod signatureInside method body
Syntaxthrows ExceptionTypethrow new Exception()
MultipleYes (comma-separated)No (one at a time)
Examplevoid m() throws IOExceptionthrow new IOException()
import java.io.*;

// throws - declares exception
void method1() throws IOException {
    // May throw IOException
}

// throw - throws exception
void method2() {
    throw new IOException("Error");  // Manually throw
}

// Both together
void method3() throws IOException {
    if (someCondition) {
        throw new IOException("Error occurred");  // throw inside
    }
}

Best Practices

  1. Declare specific exceptions, not general Exception
  2. Document why exception may occur
  3. Don’t declare unchecked exceptions
  4. Order matters when catching (not declaring)
  5. Handle at appropriate level
  6. Don’t abuse throws in main()

Quick Reference

import java.io.*;

// Declare single exception
void method1() throws IOException {
    FileReader fr = new FileReader("file.txt");
}

// Declare multiple exceptions
void method2() throws IOException, SQLException {
    // Code that may throw either
}

// Propagate exception
void method3() throws IOException {
    method1();  // Calls method that throws
}

// Handle exception (no declaration needed)
void method4() {
    try {
        method1();
    } catch (IOException e) {
        System.out.println("Handled");
    }
}

// Declare in main
public static void main(String[] args) throws IOException {
    method1();  // No need to handle
}

Common Mistakes

// ✗ Wrong - declaring unchecked (unnecessary)
void method1() throws NullPointerException {
    String str = null;
    str.length();
}

// ✗ Wrong - not handling or declaring checked
void method2() {
    FileReader fr = new FileReader("file.txt");  // Compile error
}

// ✗ Wrong - broader exception in override
class Parent {
    void method() throws IOException { }
}
class Child extends Parent {
    void method() throws Exception { }  // Error
}

// ✓ Correct - declare checked
void method3() throws IOException {
    FileReader fr = new FileReader("file.txt");
}

// ✓ Correct - handle instead of declare
void method4() {
    try {
        FileReader fr = new FileReader("file.txt");
    } catch (IOException e) {
        e.printStackTrace();
    }
}

Exam Tips

Remember:

  1. throws keyword declares exceptions
  2. Checked exceptions must be declared or handled
  3. Multiple exceptions separated by comma
  4. Unchecked don’t need declaration
  5. Caller must handle declared exceptions
  6. Can declare in main() - JVM handles
  7. Override rules - same or narrower exception
  8. Parent exception can be declared
  9. throws vs throw - different purposes
  10. Best practice - declare specific exceptions

Common Questions:

  • What is throws keyword?
  • throws vs throw?
  • How to declare multiple exceptions?
  • Can we declare unchecked exceptions?
  • What if method declares exception?
  • Rules for overriding methods?
  • Can we declare in main()?
  • Purpose of declaring exceptions?
  • What if we don’t declare checked exception?
  • Can we declare parent exception?