1. 异常处理概述
在Java中,任何代码都有可能发生异常,例如访问null对象、数组越界、除零、网络中断等等情况。如果异常一直没有被处理,程序就会崩溃。因此,Java中提供了异常处理机制来让开发者在运行时处理异常,保证程序的健壮性。
注意:异常处理是Java程序设计中极其重要的一部分,如果错误使用异常处理机制,可能会使程序的性能、可读性、可维护性大大下降。
2. 异常处理的两种方式
Java中采用了两种方式来处理异常:
2.1 抛出异常
抛出异常,即在可能出现异常的地方声明要抛出异常,并交给上层方法或调用者来处理。抛出异常使用throw关键字。抛出异常可以是Java中任何一个类的对象,不一定是{@link Throwable}子类或其子类的对象。一个方法可以抛出多种异常类型,但只能抛出{@link Throwable}或其子类异常。
public void writeFile(String path, String content) throws FileNotFoundException, IOException {
// 写文件的代码
}
2.2 捕获异常
捕获异常,即在代码中写出针对异常的处理逻辑。捕获异常使用try...catch...finally语句,try代码块中放置可能会抛出异常的代码,catch代码块中放置针对不同异常的处理逻辑,finally代码块中放置无论是否发生异常都需要执行的代码。
try {
// 可能会抛出异常的代码
} catch (FileNotFoundException e) {
// 针对FileNotFoundException的处理逻辑
} catch (IOException e) {
// 针对IOException的处理逻辑
} finally {
// 无论是否发生异常都需要执行的代码
}
3. 方法覆盖异常处理
当一个子类继承了一个父类后,如果父类中抛出了异常且子类中的方法覆盖了该方法,则子类中必须抛出与父类相同的异常,或者是它的子类型。
public class Father {
public void func() throws IOException {
// 抛出异常
}
}
public class Child extends Father {
public void func() throws FileNotFoundException {
// 抛出FileNotFoundException或其子类型
}
}
上面的代码表示,一个父类中有一个可能抛出{@link IOException}异常的方法,子类继承该父类,并覆盖了该方法,那么子类中的{@code func()}方法必须抛出{@link IOException}或其子类型的异常。
如果子类中的方法抛出的异常是父类方法抛出异常的子类,则编译器不会报错。如果子类中的方法抛出了父类方法中未声明的异常,则编译器会提示错误。
4. 示例
下面的示例演示了如何在父类和子类中抛出异常,并覆盖父类的方法。其中,父类中的方法声明要抛出{@link IOException}异常;子类中覆盖了该方法,并抛出了{@link FileNotFoundException}异常,编译没有出现错误。
public class ExceptionTest {
public static void main(String[] args) {
Father f = new Child();
try {
f.func();
} catch (IOException e) {
e.printStackTrace();
}
}
}
class Father {
public void func() throws IOException {
System.out.println("Father's func().");
throw new IOException("IOException in Father's func().");
}
}
class Child extends Father {
public void func() throws FileNotFoundException {
System.out.println("Child's func().");
throw new FileNotFoundException("FileNotFoundException in Child's func().");
}
}
程序的输出是:
Child's func().
java.io.FileNotFoundException: FileNotFoundException in Child's func().
at Child.func(ExceptionTest.java:23)
at ExceptionTest.main(ExceptionTest.java:7)
程序首先创建了一个Father类型的实例,将其赋值给f变量;然后调用{@code f.func()}方法,并在{@code try...catch}块中捕获有可能抛出的{@link IOException}异常。这个方法会调用Child的{@code func()}方法,将编译器处理异常机制转换为运行时处理异常机制,在运行时抛出异常。程序在catch代码块中打印了异常的堆栈信息。