使用 try-catch 和 throw 语句。使用 catch、 multi-catch 和 finally 子句。用 try-with-resources 语句使用自动关闭资源。创建自定义异常和自动关闭资源。

Exception

三种类型

  • java.lang.Exception排除RuntimeEcxeption
    可抛出并表示预期的错误。在某些情况下,程序可以从中恢复。一些例子是: IOException,ParseException,SQLException
  • java.lang.RuntimeException
    并表示在运行时生成的意外错误。在大多数情况下,程序无法从中恢复。一些例子是: arithmeteexception、 ClassCastException、 NullPointerException
  • java.lang.Error
    程序不应该处理的严重问题或异常情况。一些例子是: AssertionError,IOError,LinkageError,VirtualMachineError

Try-Catch

如果没有处理异常,JVM 将提供一个默认的异常处理程序来执行以下任务:
1.它打印出异常描述。
2.它打印堆栈跟踪(发生异常的方法层次结构)。
3.它导致程序终止。

  • 如果异常可以在多个块中捕获,则在定义的第一个块中捕获异常。
  • 子类之前定义了一个超类,就会产生一个编译时错误
try {
    SimpleDateFormat sdf = new SimpleDateFormat("MM/dd");
    Date date = sdf.parse("01-10");
    System.out.println(date);
} catch (Exception e) {
    System.err.println("Exception caught");
} catch (ParseException e) {
    System.err.println("ParseException caught");
}

image.png

  • 一个 catch 块被定义为一个不能被 try 块中的代码抛出的异常,那么也会产生一个错误。但是可以再方法上直接throws任何不会在方法体内抛出的Exception
try {
    SimpleDateFormat sdf = new SimpleDateFormat("MM/dd");
    Date date = sdf.parse("01-10");
    System.out.println(date);
} catch (SQLException e) { // Compile-time error
    System.err.println("ParseException caught");
}

这两个错误的原因是两个捕获块的代码将永远不会被执行(正如编译器所说的那样,它是不可达的)。
如果抛出已检查异常的代码不在 try-catch 块中,则包含该代码的方法必须在 throws 子句中声明该异常

  • 方法的调用者必须要么捕获异常,要么在 throws 子句中声明它,以此类推,直到到达程序的主方法
public class Test {
    public static void main(String[] args)
             throws ParseException {
        m1();
    }
    private static void m1() throws ParseException {
        m2();
    }
    private static void m2() throws ParseException {
        m3();
    }
    private static void m3() throws ParseException {
        m4();
    }
    private static void m4() throws ParseException {
        SimpleDateFormat sdf =
             new SimpleDateFormat("MM/dd");
        Date date = sdf.parse("01-10");
        System.out.println(date);
    }
}

多重捕获Multi-Catch

try {
    // Code that may throw one or
    // two exceptions
} catch(Exception1 | Exception2 e) {
    // Do something with the caught
    // exception using reference e
}

要么选择Exception1,要么选择Exception2

Finally

try {
    // Code that may throw an
    // exception }
finally {
    // Block that is always executed
}
  • Catch 块是可选的。可以同时拥有 catch 块或 finally
  • Finally 块始终执行,不管是在 try 块中抛出异常、在 catch 块中重新抛出异常,还是根本没有捕获异常

Multi-Catch and Finally

int res = 0;
try {
    int[] arr = new int[2];
    res = (arr[1] != 0) ? 10 / arr[1] : 10 * arr[2];
} catch (ArithmeticException e) {
    e.printStackTrace();
    return res;
} catch (IndexOutOfBoundsException e) {
    e.printStackTrace();
    return res;
}
return res;

多 catch 块允许我们用一个 catch 块捕获两个或多个异常

try {
    ...
} catch (ArithmeticException | IndexOutOfBoundsException e) {
    e.printStackTrace();
    return res;
}
  • catch 子句的末尾只有一个变量用于声明的所有异常。如果你想区分异常,你可以使用 instanceof 操作符
try {
   ...
} catch (ArithmeticException | IndexOutOfBoundsException e) {
    if(e instanceof ArithmeticException) {
        // Do something else if the exception type
        // is ArithmeticException
    }
    e.printStackTrace();
    return res;
}
  • multi-catch中变量被视为 final,这意味着您不能重新分配,只有在多重捕获时才是
    image.png
  • 不能将子类及其超类组合在同一个 multi-catch 块中
try {
    ...
} catch (ArithmeticException | RuntimeException e) {
    // The above line generates a compile-time error
    // because ArithmeticException is a subclass of
    // RuntimeException
    e.printStackTrace();
    return res;
}

类似于在子类之前的 catch 块中声明超类的情况。代码是冗余的,超类总是捕获异常。

try {
    ...
} catch (ArithmeticException | IndexOutOfBoundsException e) {
    e.printStackTrace();
} finally {
    return res;
}

Finally 块总是执行,即使捕获了异常,或者 try 或 catch 块包含一个 return 语句。因此,它通常用于关闭数据库连接或文件处理程序等资源。
只有一个例外。如果调用 System.exit () ,程序将异常终止而不执行 finally 块。但是,由于调用 System.exit ()被认为是不好的做法,这种情况很少发生

Try-With-Resources

try (AutoCloseableResource r = new AutoCloseableResource()) {
    // Code that may thrown an exception
} catch(Exception e) {
    // Handle exception
} finally {
    // Always executes
}

在 try 块完成后关闭资源

try-with-resources

自 Java 7以来,有了 try-with-resources 块,在这个块中,try 块声明一个或多个资源,这样它们就可以被关闭,而无需在 finally 块中显式地执行
及在try()括号内生命资源

try (BufferedReader br =
       new BufferedReader(new FileReader("/file.txt"))) {
    int value = 0;
    while((value = br.read()) != -1) {
        System.out.println((char)value);
    }
} catch (IOException e) {
    e.printStackTrace();
}

当 try 块执行完成后,BufferedReader 被关闭,这等价于

BufferedReader br = null;
try {
    int value = 0;
    br = new BufferedReader(new FileReader("/file.txt"));
    while((value = br.read()) != -1) {
        System.out.println((char)value);
    }
} catch (IOException e) {
    e.printStackTrace();
} finally {
    try {
        if (br != null) br.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
  • 如果声明多个资源,则必须用分号分隔
try (FileReader fr = new FileReader("/file.txt");
        BufferedReader br = new BufferedReader(fr)) {
    ...
}
  • try-with-resources 中声明的资源不能在这个块之外使用(第一个原因,它们超出了范围,第二个原因,它们在 try 块结束后关闭)
try (BufferedReader br = 
        new BufferedReader(new FileReader("/file.txt"))) {
    ...
}
String line = br.readLine(); // Compile-time error
  • 不要认为任何类在使用资源的尝试中会起作用
    在 try-with-resources 块中使用的类必须实现以下接口之一:
    java.lang.AutoCloseable
    java.io.Closable
class MyResource {
    void useResource() { }
}
...
try (MyResource r = new MyResource()) { // Compile-time error
    r.useResource()
}

image.png
image.png

void close() throws Exception;

image.png

public void close() throws IOException;

它们都声明 close ()方法,这两个接口之间唯一的实际区别是

  • Closeable 接口的 close 方法只引发 IOException 类型的异常
  • AutoCloseable 接口的 close ()方法抛出 Exception 类型的异常时(换句话说,它可以抛出几乎任何类型的异常)
    close ()方法是自动调用的,如果这个方法实际上抛出和异常,我们可以在 catch 块中捕获它
    image.png
  • 如果try块也抛出异常,结果是 try 块的异常抛出、close ()方法的异常被压制
    image.png
    只会捕获Catch{}中的异常

自定义异常Excetion

可以扩展语言的任何异常来创建我们自己的异常
将 Exception 添加到类名称中是一种约定。Error 和 Throwable 类实际上并不用于自定义异常。

总结

  • 在Java中,有三种类型的异常
    1.java.lang.Exception异常
    2.java.lang.RuntimeException异常
    3.java.lang.Error错误
  • 不需要捕获RuntimeException及其子类,因为它们不是一直都需要的。它们也被称为未检查异常。
  • Exception及其子类(RuntimeException除外)称为检查性异常,因为编译器必须检查它们是否在某个时刻被try-catch语句捕获。
  • 如果可以在多个块中捕获异常,则将在定义的第一个块中捕获该异常。
  • 类的层次结构,如果在子类之前定义了一个超类,则会生成编译时错误。
  • 如果抛出选中异常的代码不在try catch块中,则包含该代码的方法必须在throws子句中声明异常。
  • 方法的调用方必须捕获异常,或者在throws子句中声明异常,依此类推,直到到达程序的主方法为止。
  • 多重检查异常块允许我们用一个catch块捕获两个或多个不相关的异常:
  • 始终执行finally块,即使捕获到异常或try或catch块包含return语句。
  • 在try with resources块中,声明了一个或多个资源,以便仅通过实现java.lang.AutoCloseable或java.io.Closeable即可在try块结束后自动关闭这些资源:

这个家伙很懒,啥也没有留下😋