欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java入门两周旅 (Day12) Java 异常处理

程序员文章站 2022-04-05 10:00:30
...

Java 异常处理

没有程序能够始终正常运行,Java 语言的设计者也知道这一点。Java 平台提供了内置机制来处理代码未准确地按计划运行的情形。

异常 是在程序执行期间发生的破坏正常的程序指令流的事件。

异常处理 可以使用 trycatch 代码块(以及 finally)捕获错误。

异常类型

在 Java 中,异常的层次结构图如下:

Java入门两周旅 (Day12) Java 异常处理

  • Throwable
    • Error : 运行时环境发生的错误。例如,JVM 内存溢出。一般地,程序不会从错误中恢复。
    • Exception : 程序本身可以处理的异常
      • IOException
      • RuntimeException

异常分层结构

Java 语言包含一个完整的异常分层结构,它由许多类型的异常组成,这些异常划分为两大主要类别:

  • 已检查的异常(checked exceptions):已由编译器检查(表示编译器确定它们已在您代码中的某处处理过)。一般而言,这些异常是 java.lang.Exception 的直接子类。
  • 未检查的异常(也称为运行时异常unchecked / runtime exceptions):未由编译器检查。这些是 java.lang.RuntimeException 的子类。

使用 trycatchfinally

try {
    // Try to execute
} catch (ExceptionType e) {
  	// Catch exception
} finally {
    // Always executes
}

⚠️【注意】ExceptionType 要换成具体的错误类型:如 RuntimeExceptionIOException

trycatchfinally 代码块共同形成了一张捕获异常的网:

  • 首先,try 语句限定可能抛出异常的代码;
  • 捕获的异常会放到 catch 代码块(或称 异常处理函数) 中。捕获到异常时,可以尝试优雅地进行恢复,也可以退出程序(或方法);
  • 在所有尝试和捕获都完成后,会继续执行 finally 代码块,无论是否发生了异常;

例如:

package mine.java.tour;

import java.util.logging.Logger;

public class Exception {
	public static void main(String[] args) {
		Logger l = Logger.getLogger("Try-Catch-Finally");

		try {
			Integer foo = null;
			System.out.println("foo: " + foo.toString());
		} catch (RuntimeException e) {
			l.severe("Caught exception: " + e);
			System.out.println("catch");
		} finally {
			System.out.println("finally");
		}
	}
}

运行这个程序会得到如下结果:

5月 02, 2019 11:57:04 上午 mine.java.tour.Exception main
严重: Caught exception: java.lang.NullPointerException
catch
finally

多个 catch 代码块

可以拥有多个 catch代码块,但必须采用某种特定方式来搭建它们。

如果所有异常都是其他异常的子类,那么子类会按照 catch 代码块的顺序放在父类前面。

try {

} catch (IndexOutOfBoundsException e) {
    System.err.println("IndexOutOfBoundsException: " + e.getMessage());
} catch (IOException e) {
    System.err.println("Caught IOException: " + e.getMessage());
}

用一个 catch 捕获多个类型的错误

在 Java SE 7 以后,一个 catch 语句可以处理不止一个类型的异常。这个特性可以让我们避免一直写重复的代码,也让我们没有理由去catch一个过度宽泛的错误类型(例如,我们本来应该逐一处理各种不同的问题,但为了避免麻烦,直接 catch(RuntimeException e))。

我们可以把 catch 的小括号里的单个 ExceptionType 替换为逐个列出需要这个语句块处理的错误类型,每个类型之间用 竖线( | )分隔。

catch (IOException|SQLException ex) {
    logger.log(ex);
    throw ex;
}

【注】在用一个 catch 捕获多个错误的时候,这个 catch 的参数会隐含地带上 final 属性。例如在上面的例子中,catch 的参数 ex 是一个 final 的变量,因此,不能在 catch 语句块里给它赋值!

throwsthrow

  • throws : 方法可能抛出异常的声明(用在声明方法时,表示该方法可能要抛出异常)。

Checked exception 通过在声明一个方法时使用 throws 关键字加上一个可能的异常列表 来向编译器声明:

public void doSomething(int a) throws Exception1, Exception1, ... {
    ...
}

throws Exception1, Exception1, ... 只是告诉编译器这个方法可能会抛出这些异常,方法的调用者可能要处理这些异常,而这些可能异常是该函数体产生的。

  • throw 是具体向外抛异常的动作,它抛出一个异常实例。
import java.io.*;
public class className
{
  public void deposit(double amount) throws RemoteException
  {
    // Method implementation
    throw new RemoteException();
  }
  //Remainder of class definition
}

try-with-resources 代码块

当我们在 try 中使用一些资源时,不论出错与否我们都应该在最后关闭它,所以可以在finally 中完成这个关闭操作:

static String readFirstLineFromFileWithFinallyBlock(String path)
                                                     throws IOException {
    BufferedReader br = new BufferedReader(new FileReader(path));
    try {
        return br.readLine();
    } finally {
        if (br != null) br.close();
    }
}

Java SE 7 开始,还有一种更简单办法来解决问题,Java 可以自动关闭资源:

static String readFirstLineFromFile(String path) throws IOException {
    try (BufferedReader br =
                   new BufferedReader(new FileReader(path))) {
        return br.readLine();
    }
}

在 try 后面加小括号,里面声明需要的资源,在结束异常检测后(在 try 代码块超出范围时),Java 将自动处理这个资源的关闭问题。

注意,这种自动关闭的资源必须实现 java.lang.AutoCloseable 接口;如果尝试在一个没有实现该接口的资源类上实现此语法,会出错。


相关代码:

Exception.java

相关标签: Java 入门