Enums, Exceptions, and Robust Error Handling

`try`, `catch`, `finally`, `throw`, and `throws`

ReadingPreview

You are viewing a free preview lesson.

Lesson Overview

আগের lesson-এ আমরা শিখেছি:

  • Exception কী
  • Checked এবং unchecked exception
  • Exception propagation
  • Stack trace
  • throw এবং throws-এর basic difference

এখন আমরা exception handle করার actual syntax শিখব।

Java provides:

try
catch
finally
throw
throws

এই lesson-এ আমরা শিখব:

  • try block
  • Specific exception catch করা
  • Multiple catch blocks
  • Catch ordering
  • Multi-catch
  • finally
  • Exception rethrow করা
  • Exception wrapping
  • Original cause preserve করা
  • Return statement এবং finally
  • Resource cleanup
  • Try-with-resources-এর introduction
  • কখন exception locally handle করা উচিত
  • কখন caller-এর কাছে propagate করা উচিত

Learning Objectives

এই lesson শেষে আপনি পারবেন:

  • try-catch block লিখতে
  • Specific exception handle করতে
  • Multiple failure types আলাদাভাবে process করতে
  • Correct catch order maintain করতে
  • finally block ব্যবহার করতে
  • Exception rethrow এবং wrap করতে
  • Original cause preserve করতে
  • Checked exception catch বা declare করতে
  • Try-with-resources দিয়ে resource safely close করতে
  • Swallowed এবং misleading handling avoid করতে

The try Block

যে code exception throw করতে পারে, তাকে try block-এর মধ্যে রাখা যায়।

try {
    int result =
            10 / 0;

    System.out.println(
            result
    );
}

try একা ব্যবহার করা যায় না।

এর সঙ্গে অন্তত একটি থাকতে হবে:

catch
finally

বা দুটোই।


Basic try-catch

try {
    int result =
            10 / 0;

    System.out.println(
            result
    );
} catch (
        ArithmeticException exception
) {
    System.out.println(
            "Division by zero is not allowed."
    );
}

Output:

Division by zero is not allowed.

Exception catch হওয়ায় application uncontrolledভাবে terminate করেনি।


How Control Flow Works

try {
    System.out.println(
            "Before"
    );

    int result =
            10 / 0;

    System.out.println(
            "After"
    );
} catch (
        ArithmeticException exception
) {
    System.out.println(
            "Handled"
    );
}

System.out.println(
        "Finished"
);

Output:

Before
Handled
Finished

This does not print:

After

Exception throw হওয়ার সঙ্গে সঙ্গে remaining try statements skip হয়।


Catch Parameter

catch (
        ArithmeticException exception
)

এখানে:

ArithmeticException → Exception type
exception           → Local variable

Catch block-এর মধ্যে ব্যবহার করা যায়:

exception.getMessage()
exception.getCause()
exception.printStackTrace()

Reading the Exception Message

try {
    Integer.parseInt(
            "Java"
    );
} catch (
        NumberFormatException exception
) {
    System.out.println(
            exception.getMessage()
    );
}

Possible output:

For input string: "Java"

Message useful হতে পারে, কিন্তু user-facing response হিসেবে raw library message সবসময় appropriate নয়।


Catch Only Matching Types

try {
    int result =
            10 / 0;
} catch (
        NumberFormatException exception
) {
    System.out.println(
            "Invalid number."
    );
}

ArithmeticException এবং NumberFormatException different types।

এই catch failure handle করবে না।

Exception caller-এর দিকে propagate করবে।


Catching a Parent Exception

Because:

ArithmeticException extends RuntimeException

This catches it:

try {
    int result =
            10 / 0;
} catch (
        RuntimeException exception
) {
    System.out.println(
            "Runtime failure."
    );
}

And this also catches it:

catch (
        Exception exception
)

But broader catches lose precision।

Prefer the most specific type the current layer can meaningfully handle।


Specific Catch Is Better

Weak:

try {
    parseCoursePrice(
            input
    );
} catch (
        Exception exception
) {
    System.out.println(
            "Invalid price."
    );
}

This may incorrectly label:

  • NullPointerException
  • Database failure
  • Programming bug
  • Number parsing failure

as the same problem।

Better:

try {
    parseCoursePrice(
            input
    );
} catch (
        NumberFormatException exception
) {
    System.out.println(
            "Price must be a valid number."
    );
}

Multiple catch Blocks

A try block different exception types throw করতে পারে।

try {
    String value =
            values.get(
                    index
            );

    int number =
            Integer.parseInt(
                    value
            );

    System.out.println(
            number
    );
} catch (
        IndexOutOfBoundsException exception
) {
    System.out.println(
            "The selected index does not exist."
    );
} catch (
        NumberFormatException exception
) {
    System.out.println(
            "The selected value is not a number."
    );
}

Only the first matching catch executes।


Catch Ordering

Child exception catch parent exception-এর আগে থাকতে হবে।

Correct:

try {
    // Operation
} catch (
        NumberFormatException exception
) {
    // Specific handling
} catch (
        RuntimeException exception
) {
    // Broader fallback
}

Incorrect:

try {
    // Operation
} catch (
        RuntimeException exception
) {
    // Catches NumberFormatException too
} catch (
        NumberFormatException exception
) {
    // Unreachable
}

Compiler rejects the second catch because parent catch already handles every NumberFormatException


Most Specific to Most General

Recommended order:

Specific child exception
↓
Broader parent exception
↓
General fallback, only if necessary

Example:

catch (
        FileNotFoundException exception
) {
} catch (
        IOException exception
) {
} catch (
        Exception exception
) {
}

Multi-Catch

If multiple exception types need exactly the same handling:

try {
    // Operation
} catch (
        NumberFormatException
        | IndexOutOfBoundsException exception
) {
    System.out.println(
            "Input could not be processed."
    );
}

This avoids duplicate catch blocks।


Multi-Catch Restrictions

Types in one multi-catch cannot have a parent-child relationship।

Invalid:

catch (
        RuntimeException
        | NumberFormatException exception
) {
}

Because NumberFormatException is already a RuntimeException


When Not to Combine Catches

Do not use multi-catch when failures need different responses।

Weak:

catch (
        NumberFormatException
        | IOException exception
) {
    System.out.println(
            "Invalid input."
    );
}

An IOException may not mean invalid input।

Separate them when meaning or recovery differs।


The finally Block

finally runs after try and catch flow completes, whether exception occurred or not।

try {
    System.out.println(
            "Trying"
    );
} finally {
    System.out.println(
            "Cleanup"
    );
}

Output:

Trying
Cleanup

try-catch-finally

try {
    int result =
            10 / 0;
} catch (
        ArithmeticException exception
) {
    System.out.println(
            "Handled"
    );
} finally {
    System.out.println(
            "Always runs"
    );
}

Output:

Handled
Always runs

finally Without a Matching Catch

try {
    int result =
            10 / 0;
} finally {
    System.out.println(
            "Cleanup"
    );
}

finally runs।

Then ArithmeticException continues propagating।

Output starts with:

Cleanup

but application still fails unless an outer caller catches the exception।


Typical Uses of finally

Historically, finally commonly handled cleanup:

Close file
Close stream
Release lock
Restore temporary state
Release connection

Example:

Resource resource =
        null;

try {
    resource =
            openResource();

    useResource(
            resource
    );
} finally {
    if (resource != null) {
        resource.close();
    }
}

Modern Java usually prefers try-with-resources for closeable resources।


finally and Return

public static int calculate() {
    try {
        return 10;
    } finally {
        System.out.println(
                "Finally"
        );
    }
}

The method prints:

Finally

then returns:

10

finally executes before method completion।


Never Return from finally

Dangerous:

public static int calculate() {
    try {
        return 10;
    } finally {
        return 20;
    }
}

Result:

20

The finally return overrides the try return।

Even worse, it can suppress an exception।


finally Can Hide an Exception

public static int calculate() {
    try {
        throw new IllegalStateException(
                "Failure"
        );
    } finally {
        return 20;
    }
}

The exception is suppressed by the return in finally

Caller receives:

20

This is extremely misleading।

Rule:

Do not return, throw a different unrelated exception, or use control-flow statements from finally unless there is a very deliberate reason.


Throwing an Exception

public static void validateLearnerId(
        long learnerId
) {
    if (learnerId <= 0) {
        throw new IllegalArgumentException(
                "Learner ID must be positive."
        );
    }
}

throw works with an exception object।

Invalid:

throw "Invalid";

Only Throwable subclasses can be thrown।


Declaring with throws

public static String readCourseContent(
        Path path
) throws IOException {
    return Files.readString(
            path
    );
}

The method passes responsibility to the caller।

Caller must:

  • Catch IOException
  • Or declare it again

Catching a Checked Exception

public static String loadContent(
        Path path
) {
    try {
        return Files.readString(
                path
        );
    } catch (
            IOException exception
    ) {
        return "";
    }
}

This compiles, but returning empty text may hide the difference between:

Actual empty file
Failed file read

Handling must preserve meaningful failure semantics।


Declaring a Checked Exception

public static String loadContent(
        Path path
) throws IOException {
    return Files.readString(
            path
    );
}

Now caller chooses how to handle the infrastructure failure।

This is often better when current method cannot recover meaningfully।


Catch or Propagate?

Catch an exception when the current layer can:

  • Recover
  • Provide a fallback that is actually valid
  • Retry safely
  • Translate to a more meaningful abstraction
  • Convert it into a clear boundary response
  • Add context and preserve the cause

Propagate when the current layer cannot make a useful decision।


Bad Recovery

try {
    return Files.readString(
            path
    );
} catch (
        IOException exception
) {
    return "";
}

This may pretend success।

If empty content is not a valid fallback, propagate or wrap the failure instead।


Valid Fallback

Suppose optional description file is genuinely optional:

public static String loadOptionalDescription(
        Path path
) {
    try {
        return Files.readString(
                path
        );
    } catch (
        NoSuchFileException exception
    ) {
        return "No description available.";
    } catch (
        IOException exception
    ) {
        throw new IllegalStateException(
                "Could not read course description.",
                exception
        );
    }
}

Missing optional file has a valid fallback।

Other I/O failures are not silently hidden।


Rethrowing the Same Exception

try {
    processEnrollment();
} catch (
        IllegalStateException exception
) {
    System.out.println(
            "Enrollment processing failed."
    );

    throw exception;
}

This logs or adds local action, then propagates the same exception।

Be careful not to log the same exception at every layer, creating duplicate noisy logs।


Rethrowing Preserves the Original Stack Trace

throw exception;

propagates the existing exception object।

Original failure location remains visible।


Avoid throw new Exception(exception.getMessage())

Weak:

catch (
        IOException exception
) {
    throw new IllegalStateException(
            exception.getMessage()
    );
}

Problems:

  • Original exception type lost
  • Original cause chain lost
  • Message may lack domain context

Better:

catch (
        IOException exception
) {
    throw new IllegalStateException(
            "Could not load course content.",
            exception
    );
}

Exception Wrapping

Wrapping means catching a lower-level exception and throwing a higher-level exception।

try {
    return Files.readString(
            path
    );
} catch (
        IOException exception
) {
    throw new IllegalStateException(
            "Could not load course content from storage.",
            exception
    );
}

Now caller sees an application-relevant failure while cause remains preserved।


Why Wrap an Exception?

Lower-level API may expose implementation details:

IOException
SQLException
SocketTimeoutException

Higher-level service may want to expose:

CourseContentLoadException
CourseRepositoryException
PaymentProcessingException

This reduces coupling between abstraction layers।

Custom exceptions come in a later lesson।


Add Useful Context When Wrapping

Weak:

throw new IllegalStateException(
        "Failed.",
        exception
);

Better:

throw new IllegalStateException(
        "Could not load content for course "
        + courseCode
        + ".",
        exception
);

Include safe context that helps diagnosis।

Do not include secrets or private data।


Catching and Throwing the Same Type Unnecessarily

Redundant:

try {
    saveCourse();
} catch (
        IOException exception
) {
    throw exception;
}

This adds no value।

Simply allow propagation:

saveCourse();

Catch only when you add meaningful handling, translation, cleanup, or context।


Exception Variable Naming

Prefer:

exception

or a descriptive name:

ioException
validationException

Avoid meaningless:

e

in teaching and application code where readability matters।

Short names may be common, but clear names improve comprehension।


Catch Block Scope

The exception variable exists only inside its catch block।

try {
    // Operation
} catch (
        IOException exception
) {
    System.out.println(
            exception.getMessage()
    );
}

// exception is not accessible here

Nested try-catch

Possible:

try {
    try {
        loadCourse();
    } catch (
        IOException exception
    ) {
        recoverFromMissingFile();
    }

    publishCourse();
} catch (
        IllegalStateException exception
) {
    reportPublicationFailure();
}

But deeply nested handling becomes difficult to follow।

Prefer extracting focused methods when possible।


One try Block Should Be Focused

Weak:

try {
    parseInput();
    loadDatabase();
    calculatePrice();
    sendEmail();
    writeFile();
} catch (
        Exception exception
) {
    System.out.println(
            "Operation failed."
    );
}

It is unclear which operation failed and what can be recovered।

Better to create meaningful boundaries and catch specific failures near the layer that understands them।


Avoid Huge try Blocks

Large try blocks:

  • Catch unrelated exceptions
  • Make failure origin less obvious
  • Encourage broad catch
  • Mix recovery policies

Keep protected operation focused।


Try-With-Resources

Resources such as:

File readers
Streams
Database resources
Network streams

often need closing।

Java provides:

try (
        Resource resource =
                openResource()
) {
    useResource(
            resource
    );
}

The resource is closed automatically।


A File Reading Example

public static String readFirstLine(
        Path path
) throws IOException {
    try (
            BufferedReader reader =
                    Files.newBufferedReader(
                            path
                    )
    ) {
        return reader.readLine();
    }
}

When the block completes:

  • Normally
  • Through return
  • Through exception

reader.close() is called automatically।


Why Try-With-Resources Is Better

Manual cleanup:

BufferedReader reader =
        null;

try {
    reader =
            Files.newBufferedReader(
                    path
            );

    return reader.readLine();
} finally {
    if (reader != null) {
        reader.close();
    }
}

Problems:

  • More code
  • Cleanup itself may throw
  • Null checks required
  • Easy to forget
  • Multiple resources become complicated

Try-with-resources is clearer and safer।


AutoCloseable

A resource can be used in try-with-resources if it implements:

AutoCloseable

or a compatible subtype such as:

Closeable

Many Java I/O and database resource types implement this contract।


Multiple Resources

try (
        InputStream input =
                Files.newInputStream(
                        sourcePath
                );

        OutputStream output =
                Files.newOutputStream(
                        targetPath
                )
) {
    input.transferTo(
            output
    );
}

Resources close automatically in reverse declaration order।

output closes first
input closes second

Suppressed Exceptions

Suppose:

  • Main operation throws
  • Resource closing also throws

Java preserves the main exception and attaches close failure as a suppressed exception।

It can be inspected using:

exception.getSuppressed()

This is another reason try-with-resources is safer than manual cleanup।


finally Is Still Useful

Try-with-resources replaces many resource-closing uses, but finally can still be useful for:

  • Releasing a lock
  • Restoring temporary state
  • Clearing thread-local context
  • Ending timing measurement
  • Cleanup not modeled by AutoCloseable

Use it carefully and avoid hiding the original failure।


Handling Exceptions at a Boundary

Suppose application service throws:

IllegalArgumentException

An API boundary may catch it and convert it to:

HTTP 400 Bad Request

A missing resource may become:

HTTP 404 Not Found

An infrastructure failure may become:

HTTP 500 Internal Server Error

Domain and infrastructure code should not directly return HTTP responses unless that is their responsibility।

Boundaries translate failures into transport-specific results।


Do Not Expose the Same Message Everywhere

Internal exception:

Database connection refused at db-internal:5432

External response:

Unable to process the request right now.

Detailed cause belongs in secure logs।

User-facing response should be safe and actionable।


Complete Example: Loading Course Content

CourseContentLoader.java

package io.liveklass.content;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;

public final class CourseContentLoader {

    public String load(
            Path path
    ) {
        if (path == null) {
            throw new IllegalArgumentException(
                    "Content path is required."
            );
        }

        try {
            return Files.readString(
                    path
            );
        } catch (
                IOException exception
        ) {
            throw new IllegalStateException(
                    "Could not load course content from "
                    + path.getFileName()
                    + ".",
                    exception
            );
        }
    }
}

Calling the Loader

public class Main {

    public static void main(
            String[] args
    ) {
        CourseContentLoader loader =
                new CourseContentLoader();

        try {
            String content =
                    loader.load(
                            Path.of(
                                    "course.md"
                            )
                    );

            System.out.println(
                    content
            );
        } catch (
                IllegalArgumentException exception
        ) {
            System.out.println(
                    "Invalid request: "
                    + exception.getMessage()
            );
        } catch (
                IllegalStateException exception
        ) {
            System.out.println(
                    "Content could not be loaded."
            );

            exception.printStackTrace();
        } finally {
            System.out.println(
                    "Load attempt finished."
            );
        }
    }
}

Possible Output for a Missing File

Content could not be loaded.
Load attempt finished.

Stack trace also shows:

IllegalStateException:
Could not load course content from course.md.

Caused by:
NoSuchFileException

Design Review

Why Validate path Before try?

Null path is a caller contract violation।

It is not a file I/O failure।

Keeping validation outside the try prevents unrelated handling from mixing।


Why Catch IOException?

The loader translates storage-level failures into an application-level failure।


Why Preserve the Cause?

The caller sees meaningful context while developers retain the original file failure।


Why Does finally Print Last?

It runs after normal or exceptional handling completes।


Complete Example: Parsing Learner Input

public static int parseCompletedLessons(
        String value
) {
    if (
            value == null
            || value.isBlank()
    ) {
        throw new IllegalArgumentException(
                "Completed lesson count is required."
        );
    }

    try {
        int count =
                Integer.parseInt(
                        value.strip()
                );

        if (count < 0) {
            throw new IllegalArgumentException(
                    "Completed lesson count cannot be negative."
            );
        }

        return count;
    } catch (
            NumberFormatException exception
    ) {
        throw new IllegalArgumentException(
                "Completed lesson count must be a valid integer.",
                exception
        );
    }
}

Why Wrap NumberFormatException?

Caller should understand the domain field:

Completed lesson count

not only Java parsing terminology।

The cause remains available for debugging।


Be Careful Catching Your Own Exception

In the previous method, IllegalArgumentException thrown for negative count is not caught by:

catch (
        NumberFormatException exception
)

This is good।

If catch were:

catch (
        IllegalArgumentException exception
)

it would also catch the manually thrown negative-count failure and potentially wrap it incorrectly।

Catch scope and type both matter।


Keep Only Parsing Inside the Parsing Catch

Even clearer:

public static int parseCompletedLessons(
        String value
) {
    if (
            value == null
            || value.isBlank()
    ) {
        throw new IllegalArgumentException(
                "Completed lesson count is required."
        );
    }

    int count;

    try {
        count =
                Integer.parseInt(
                        value.strip()
                );
    } catch (
            NumberFormatException exception
    ) {
        throw new IllegalArgumentException(
                "Completed lesson count must be a valid integer.",
                exception
        );
    }

    if (count < 0) {
        throw new IllegalArgumentException(
                "Completed lesson count cannot be negative."
        );
    }

    return count;
}

The try block now protects only the operation that can produce the parsing failure।


Common Mistakes

Catching Too Broadly

catch (
        Exception exception
)

may hide unrelated problems।


Wrong Catch Order

Parent exception before child makes child catch unreachable।


Empty Catch Block

Swallows the failure।


Returning Success After Catching a Failure

Creates contradictory behavior।


Returning from finally

Can override return values and suppress exceptions।


Throwing a New Exception Without the Cause

Loses the original failure chain।


Catching Only to Rethrow Without Adding Value

Creates unnecessary code।


Using a False Fallback

Returning empty content after a failed read may pretend success।


Huge try Blocks

Mix unrelated failure sources।


Logging the Same Exception at Every Layer

Creates duplicate noisy logs।


Manually Closing Resources When Try-With-Resources Fits

Adds avoidable complexity।


Catching Throwable

Can hide serious JVM errors।


Practice Exercises

Exercise 1: Parse Price

Create:

static long parsePrice(
        String value
)

Requirements:

  • Blank input → IllegalArgumentException
  • Non-numeric input → wrap NumberFormatException
  • Negative number → IllegalArgumentException
  • Preserve parsing cause

Exercise 2: Multiple Catch Blocks

Write a method that:

  • Reads an element from a list by index
  • Parses it as integer
  • Handles invalid index and invalid number separately

Exercise 3: Catch Ordering

Explain why this fails:

catch (
        RuntimeException exception
) {
} catch (
        NumberFormatException exception
) {
}

Correct the order।


Exercise 4: Finally Behavior

Predict whether finally runs when:

  1. try completes normally
  2. try returns
  3. try throws and catch handles
  4. try throws and no catch matches

Exercise 5: Preserve Cause

Catch:

IOException

and wrap it in:

IllegalStateException

with message:

Could not load lesson content.

Exercise 6: Try-With-Resources

Read the first line of a file using:

BufferedReader

and try-with-resources।


Exercise 7: Find the Bug

Explain what is wrong:

public boolean save() {
    try {
        repository.save();
        return true;
    } catch (
            Exception exception
    ) {
        exception.printStackTrace();
    }

    return true;
}

Exercise 8: Result or Exception

Choose behavior for:

  1. Optional course search found nothing
  2. Invalid negative course ID
  3. File cannot be read
  4. Duplicate enrollment is expected
  5. Impossible internal state
  6. User enters non-numeric price

Explain whether to return a result, throw, catch, or translate।


Predict the Result

Question 1

try {
    System.out.println(
            "A"
    );

    int result =
            10 / 0;

    System.out.println(
            "B"
    );
} catch (
        ArithmeticException exception
) {
    System.out.println(
            "C"
    );
} finally {
    System.out.println(
            "D"
    );
}

System.out.println(
        "E"
);

Answer

A
C
D
E

Question 2

public static int value() {
    try {
        return 10;
    } finally {
        System.out.println(
                "Finished"
        );
    }
}

Answer

Prints:

Finished

Returns:

10

Question 3

public static int value() {
    try {
        return 10;
    } finally {
        return 20;
    }
}

Answer

Returns:

20

The finally return overrides the try return।

This design should be avoided।


Question 4

try {
    Integer.parseInt(
            "Java"
    );
} catch (
        RuntimeException exception
) {
    System.out.println(
            "Runtime"
    );
} catch (
        NumberFormatException exception
) {
    System.out.println(
            "Number"
    );
}

Answer

The code does not compile।

NumberFormatException catch is unreachable because the parent RuntimeException catch appears first।


Question 5

try {
    throw new IllegalStateException(
            "Failure"
    );
} finally {
    System.out.println(
            "Cleanup"
    );
}

Answer

Prints:

Cleanup

Then the IllegalStateException propagates।


Knowledge Check

Question 1

What does a try block contain?

Question 2

What happens to remaining try statements after an exception?

Question 3

How is a matching catch selected?

Question 4

Why must child exception catches appear before parent catches?

Question 5

What is multi-catch?

Question 6

When does finally run?

Question 7

Why should you avoid returning from finally?

Question 8

What is the difference between throw and throws?

Question 9

When should an exception be caught locally?

Question 10

When should it be propagated?

Question 11

What is exception wrapping?

Question 12

Why preserve the original cause?

Question 13

What is try-with-resources?

Question 14

Which interface makes a resource compatible with try-with-resources?

Question 15

Why should a try block remain focused?


Knowledge Check Answers

Answer 1

Code whose exceptional outcome needs handling, cleanup, or translation।

Answer 2

They are skipped and control moves to a matching catch or outward propagation।

Answer 3

Java chooses the first compatible catch block in declaration order।

Answer 4

A parent catch already accepts every child exception, making later child catches unreachable।

Answer 5

One catch block handling multiple unrelated exception types with the same behavior।

Answer 6

After try and matching catch flow, including normal completion, return, or exception propagation in most ordinary cases।

Answer 7

It can override normal return values and suppress exceptions।

Answer 8

throw signals a specific exception object; throws declares possible propagation in a method signature।

Answer 9

When the current layer can recover, provide a valid fallback, translate, or add meaningful context।

Answer 10

When the current layer cannot make a useful handling decision।

Answer 11

Catching a lower-level exception and throwing a higher-level exception, usually with the original cause।

Answer 12

It preserves the technical origin and full debugging chain।

Answer 13

A Java construct that automatically closes compatible resources after the block।

Answer 14

AutoCloseable

Answer 15

Focused blocks avoid mixing unrelated failure sources and enable precise handling।


Lesson Summary

এই lesson-এ আমরা শিখেছি:

  • try exception-prone operationকে handling boundary দেয়
  • Matching catch exceptional flow handle করে
  • Remaining try statements exception-এর পরে execute হয় না
  • Specific exception catches broad catches-এর চেয়ে safer
  • Multiple catches different failures differently handle করতে পারে
  • Child catches parent catches-এর আগে থাকতে হয়
  • Multi-catch same handling share করা unrelated exceptions combine করে
  • finally normal এবং exceptional flow-এর পরে cleanup করতে পারে
  • finally-তে return exception এবং result hide করতে পারে
  • throw specific exception signal করে
  • throws possible propagation declare করে
  • Checked exceptions catch বা declare করতে হয়
  • Catch only when current layer can meaningfully handle
  • Invalid fallback failure hide করতে পারে
  • Rethrowing same exception propagation continue করে
  • Wrapping lower-level failure higher-level context provide করে
  • Original cause constructor-এ pass করা উচিত
  • Catching only to rethrow without adding value unnecessary
  • Large try blocks unrelated failures mix করে
  • Try-with-resources closeable resources automatically close করে
  • AutoCloseable resources try-with-resources support করে
  • Multiple resources reverse order-এ close হয়
  • Suppressed exceptions cleanup failure preserve করতে পারে
  • Boundary layers internal exceptionsকে user-safe responses-এ translate করতে পারে
  • Handling means correct observable outcome, শুধু stack trace print করা নয়

Next Lesson

পরবর্তী lesson:

Checked vs Unchecked Exceptions

আমরা শিখব:

  • Compiler enforcement
  • RuntimeException
  • Checked exception contracts
  • API design trade-offs
  • Recoverability myths
  • Validation failures
  • Infrastructure failures
  • Wrapping checked exceptions
  • When custom exceptions should be checked or unchecked
  • Avoiding exception declaration pollution