杰瑞科技汇

Java异常捕获时,父类异常能否先于子类被catch?

Of course! Let's dive deep into try-catch blocks in Java, which are the foundation of exception handling.

Java异常捕获时,父类异常能否先于子类被catch?-图1
(图片来源网络,侵删)

What is an Exception?

In Java, an exception is an event that disrupts the normal flow of the program. It's an object that is "thrown" when an error occurs. These can be things like:

  • Trying to divide by zero (ArithmeticException).
  • Trying to access an array index that doesn't exist (ArrayIndexOutOfBoundsException).
  • Trying to open a file that doesn't exist (FileNotFoundException).
  • Trying to cast an object to a type it's not (ClassCastException).

If an exception is not handled, the program will crash and print an error message to the console.


The try-catch Block: The Basic Syntax

The try-catch block is how you "handle" an exception. You wrap code that might throw an exception in a try block and then provide one or more catch blocks to "catch" and handle the specific exception.

Basic Syntax:

try {
    // Code that might throw an exception
    // (This is the "risky" code)
} catch (ExceptionType1 e1) {
    // Code to handle ExceptionType1
} catch (ExceptionType2 e2) {
    // Code to handle ExceptionType2
} finally {
    // Code that always runs, whether an exception occurred or not.
    // This is optional.
}

A Simple, Practical Example

Let's look at a classic example: division by zero.

Java异常捕获时,父类异常能否先于子类被catch?-图2
(图片来源网络,侵删)
public class DivisionExample {
    public static void main(String[] args) {
        int numerator = 10;
        int denominator = 0;
        // We know that dividing by zero will cause an ArithmeticException.
        // So, we put this risky code inside a 'try' block.
        try {
            int result = numerator / denominator;
            System.out.println("The result is: " + result);
        } 
        // The 'catch' block "catches" the specific exception type.
        // 'e' is a variable that holds the exception object.
        catch (ArithmeticException e) {
            // This code will only run if an ArithmeticException occurs in the try block.
            System.out.println("Error: Cannot divide by zero!");
            // You can also print the detailed error message from the exception object:
            // System.out.println("Error details: " + e.getMessage());
        }
        System.out.println("The program continues to run after the catch block.");
    }
}

Output:

Error: Cannot divide by zero!
The program continues to run after the catch block.

Without the try-catch block, the program would have crashed and printed a stack trace, and the final System.out.println line would never have been executed.


Key Concepts Explained

a) The try Block

This is where you place the code that you suspect might throw an exception. You can't have a try block by itself; it must be followed by at least one catch block.

b) The catch Block

A catch block "catches" an exception if it is of the type specified in the parentheses.

Java异常捕获时,父类异常能否先于子类被catch?-图3
(图片来源网络,侵删)
  • catch (ArithmeticException e): This block will only catch exceptions of type ArithmeticException or its subclasses.
  • The variable e (you can name it anything, but e or ex is common) is a reference to the exception object. This object contains useful information, such as:
    • e.getMessage(): A string describing the error.
    • e.toString(): The name of the exception class and the message.
    • e.printStackTrace(): Prints the full "stack trace" to the console, which is very useful for debugging.

c) Multiple catch Blocks

If a try block can throw more than one type of exception, you can provide multiple catch blocks. The order is important: more specific exceptions must be caught before more general ones.

public class MultipleCatchExample {
    public static void main(String[] args) {
        String[] names = { "Alice", "Bob" };
        String name = null;
        try {
            // This line could throw an ArrayIndexOutOfBoundsException
            System.out.println(names[2]); 
            // This line could throw a NullPointerException
            System.out.println(name.length()); 
        } 
        // This catch block must come FIRST because it's more specific.
        // ArrayIndexOutOfBoundsException is a subclass of IndexOutOfBoundsException.
        catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("Error: Array index is out of bounds.");
        }
        // This catch block will catch NullPointerException.
        catch (NullPointerException e) {
            System.out.println("Error: Tried to use a null object.");
        }
        // This is a general catch-all. It should be LAST.
        catch (Exception e) {
            System.out.println("An unexpected error occurred.");
        }
    }
}

Output:

Error: Array index is out of bounds.

The first error in the try block was an ArrayIndexOutOfBoundsException, so the first matching catch block was executed.

d) The finally Block

The finally block is optional, but if it's present, it will always execute, regardless of whether an exception was thrown or caught. It's typically used for cleanup operations, like closing a file or a database connection.

public class FinallyExample {
    public static void main(String[] args) {
        try {
            int[] numbers = {1, 2, 3};
            System.out.println(numbers[5]);
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("Caught the array exception.");
        } finally {
            // This code runs no matter what.
            System.out.println("This is the 'finally' block. It always runs.");
        }
        System.out.println("Program finished.");
    }
}

Output:

Caught the array exception.
This is the 'finally' block. It always runs.
Program finished.

Even if no exception had occurred, the finally block would still have run.


The Exception Hierarchy (Why Order Matters)

All exceptions in Java are subclasses of the Throwable class. The hierarchy looks like this:

java.lang.Object
  └── java.lang.Throwable
      ├── java.lang.Error (For serious JVM errors, not typically caught)
      └── java.lang.Exception (For exceptions you can and should catch)
          ├── java.lang.RuntimeException (Unchecked exceptions)
          │   ├── ArithmeticException
          │   ├── NullPointerException
          │   ├── ArrayIndexOutOfBoundsException
          │   └── ...
          └── java.lang.Exception (Checked exceptions)
              ├── IOException
              │   └── FileNotFoundException
              └── SQLException
                  └── ...
  • Checked Exceptions: These are exceptions that the compiler forces you to handle (using try-catch or by declaring them with throws). They are typically related to external factors, like files or network connections (e.g., IOException, SQLException).
  • Unchecked Exceptions (RuntimeExceptions): These are exceptions that the compiler does not force you to handle. They usually indicate programming bugs (e.g., dividing by zero, null pointer access). While you can catch them, it's often better to fix the bug in your code.

Because of this hierarchy, a catch (Exception e) block will catch any subclass of Exception. If you put it first, it will "steal" all the exceptions, and more specific catch blocks below it will never be reached. That's why specific catch blocks must come before general ones.


Best Practices

  1. Be Specific: Catch the most specific exception you can. Don't just use catch (Exception e) if you're only expecting an IOException.
  2. Don't Swallow Exceptions: Avoid empty catch blocks like catch (Exception e) { }. If you catch an exception, you should do something with it—at a minimum, log it.
  3. Use finally for Cleanup: Use the finally block to release resources like file handles, database connections, or network sockets.
  4. Log Exceptions: Use a logging framework (like SLF4J with Logback or Log4j2) to record exceptions. This is much better than just printing to the console, as it allows you to control the log level and output destination.
  5. Document Exceptions: If a method can throw a checked exception, document it in the method's Javadoc using @throws.
分享:
扫描分享到社交APP
上一篇
下一篇