CodeGym /Courses /JAVA 25 SELF /finally and throw: cleanup and throwing exceptions

finally and throw: cleanup and throwing exceptions

JAVA 25 SELF
Level 11 , Lesson 3
Available

1. Introduction to the finally block

When you work with resources — files, network connections, databases — it is important to be sure they will be closed or released always, even if an error occurs during processing. Java provides a special block for this — finally.

How does finally work?

The finally block is part of the try-catch-finally construct. The code inside finally always runs (if it’s present) — regardless of whether an exception occurred or not. Even if there is a return in try or an exception was thrown — finally will still execute (unless you power off the computer or forcibly terminate the program via System.exit(0)).

Syntax:

try {
    // Code where an exception may occur
} catch (ExceptionType e) {
    // Error handling
} finally {
    // This code will always run!
}

Example

try {
    System.out.println("Start");
    int result = 10 / 0; // an error will occur here
    System.out.println("Result: " + result);
} catch (ArithmeticException e) {
    System.out.println("Error: division by zero");
} finally {
    System.out.println("This code will run no matter what");
}

Execution result:

Start
Error: division by zero
This code will run no matter what

What happens?

  1. In try we attempt to divide two numbers and get an error.
  2. If an error occurs during division — catch handles it.
  3. But! In any case finally runs and writes a message to the console.

2. finally without catch

There are 3 possible variants of the construct:

  • Full: try-catch-finally
  • Without finally: try-catch
  • Without catch: try-finally

The third option is used when a method one level up will catch and handle the error. But the finally block is needed to guarantee that certain code will run:

  • Closing files, network connections, databases.
  • Releasing any resources (for example, locks).
  • Logging: recording information about the completion of an operation.

Example:

try {
    System.out.println("Dividing numbers");
    int result = 10 / 0;   // error!
    System.out.println("Result: " + result);
} finally {
    System.out.println("finally block executed");
}

Result:

Dividing numbers
finally block executed
Exception in thread "main" java.lang.ArithmeticException: / by zero

When does finally NOT run?

It runs almost always. Exceptions — if:

  1. The program is forcibly terminated using: System.exit(0).
  2. The thread executing finally is forcibly “killed”.
  3. The computer is powered off.

3. The throw statement: how to generate an exception manually

Sometimes Java throws exceptions on its own (for example, division by zero, out-of-bounds array access). But there are situations when you want to explicitly say: “This is an error! I cannot continue execution!” For this, Java has the throw statement.

Analogy: If you are in a store and see an expired product — you file a complaint. Likewise in code: if something is wrong — you throw an exception.

throw syntax

throw new ExceptionType("Error message");

ExceptionType is any class that extends Throwable (typically Exception or RuntimeException). In parentheses is a message that helps you understand what went wrong.

Example: validating method arguments

public static int safeDivide(int a, int b) {
    if (b == 0) {
        throw new IllegalArgumentException("Divisor cannot be zero");
    }
    return a / b;
}

Usage:

public static void main(String[] args) {
    try {
        int result = safeDivide(10, 0);
        System.out.println("Result: " + result);
    } catch (IllegalArgumentException e) {
        System.out.println("Error: " + e.getMessage());
    }
}

Result:

Error: Divisor cannot be zero

When to use throw?

  • Validating method arguments (for example, when null or invalid data is passed).
  • Validating an object's state (for example, attempting to withdraw money from an account that has €0).
  • Inside catch — if you want to rethrow the exception further (for example, to add additional information).

4. Combining try-catch-finally and throw

Sometimes these constructs work together. For example, you catch one error, and then decide to throw your own, more informative one.

public static int parseAndDivide(String text, int divisor) {
    try {
        int number = Integer.parseInt(text);
        if (divisor == 0) {
            throw new IllegalArgumentException("Divisor cannot be zero");
        }
        return number / divisor;
    } catch (NumberFormatException e) {
        throw new IllegalArgumentException("The string '" + text + "' is not a number");
    } finally {
        System.out.println("Attempt to process string: " + text);
    }
}

Usage:

try {
    int result = parseAndDivide("42a", 2);
    System.out.println("Result: " + result);
} catch (IllegalArgumentException e) {
    System.out.println("Error: " + e.getMessage());
}

Result:

Attempt to process string: 42a
Error: The string '42a' is not a number

Important nuance: return and finally

Even if there is a return in the try block, finally will still run!

public static int getValue() {
    try {
        return 10;
    } finally {
        System.out.println("finally will still run!");
    }
}

Calling getValue() will print:

finally will still run!

5. Common mistakes when using finally and throw

Mistake #1: forgot to close a resource without finally.
A very common issue: you opened a file and didn’t close it — you got a resource leak. Always use finally (or try-with-resources, which we will discuss later).

Mistake #2: threw an exception but didn’t handle it.
If you throw an exception using throw but don’t catch it anywhere (no try-catch), the program will crash. Always think about who will catch your exception.

Mistake #3: return in finally.
If you mistakenly write return inside finally, it will override all previous return or throw. This can lead to very hard-to-find bugs. Doing this is strongly discouraged!

public int tricky() {
    try {
        return 1;
    } finally {
        return 2; // DANGEROUS: 2 will be returned, not 1!
    }
}

Result: 2 will be returned even though try had 1.

Mistake #4: losing exception information.
If you catch one exception and then throw a new one without preserving information about the original (e), you lose the stack trace, which makes debugging harder. It’s better to write:

catch (NumberFormatException e) {
    throw new IllegalArgumentException("Conversion error", e);
}
1
Task
JAVA 25 SELF, level 11, lesson 3
Locked
Cleaning Robot and Its Completion Report 🧹
Cleaning Robot and Its Completion Report 🧹
1
Task
JAVA 25 SELF, level 11, lesson 3
Locked
Scoring system: positive values only! 🏅
Scoring system: positive values only! 🏅
1
Task
JAVA 25 SELF, level 11, lesson 3
Locked
Critical module and emergency termination with report 💥
Critical module and emergency termination with report 💥
1
Task
JAVA 25 SELF, level 11, lesson 3
Locked
Username validation in the registration system 📝
Username validation in the registration system 📝
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION