Checked异常和Runtime异常
Java的异常分为两大类,Checked异常和Runtime异常,所有的RuntimeException类及其子类的实例被称为Runtime异常,不是RuntimeException类及其子类的异常实例则被称为Checked异常
Checked异常的处理方式有如下两种:
- 当前方法明确知道如何处理该异常,程序应该使用try…catch块来捕获该异常,然后在对应的catch块中修复该异常
- 当前方法不知道如何处理这种异常,应该在定义该方法时声明抛出该异常
Runtime异常则更加灵活,Runtime异常无须显示声明抛出,如果程序需要捕获Runtime异常,也可以使用try…catch代码块来实现
只有Java提供了Checked异常,它要求开发者必须注意该类异常,要么显示声明抛出,要么显示捕获并处理
使用throws声明异常
使用throws声明抛出异常的思路是,当前方法不知道如何处理这种类型的异常,该异常应该由上一级调用者处理,如果main方法也不知道如何处理这种类型的异常,也可以使用throws声明抛出异常,该异常交给JVM处理,而JVM对异常的处理方式是打印异常的跟踪栈信息,并终止程序运行,这就是程序在遇到异常后自动结束的原因
throws声明抛出只能在方法签名中使用,throws可以声明抛出多个异常类,多个异常类用逗号隔开,其语法如下,一旦使用throws语句声明抛出该异常,程序就无需使用try…catch代码块来捕获该异常了
throws ExceptionClass1, ExceptionClass2...
import java.io.*;
public class ThrowsTest
{
public static void main(String[] args) throws IOException
{
var fis = new FileInputStream("a.txt");
}
}
如果某段代码调用了一个带throws声明的方法,该方法声明抛出了Checked异常,则表明该方法希望它的调用者来处理该异常,也就是说,调用该方法的时候要么方法try代码块中显示的捕获该异常,要么放在另一个带throws声明抛出的方法中
import java.io.*;
public class ThrowsTest2
{
public static void main(String[] args) throws Exception
{
// 因为test()方法声明抛出IOException异常,
// 所以调用该方法的代码要么处于try...catch块中,
// 要么处于另一个带throws声明抛出的方法中。
test();
}
public static void test() throws IOException
{
// 因为FileInputStream的构造器声明抛出IOException异常,
// 所以调用FileInputStream的代码要么处于try...catch块中,
// 要么处于另一个带throws声明抛出的方法中。
var fis = new FileInputStream("a.txt");
}
}
方法重写时声明抛出异常的限制
使用throws声明抛出异常时有一个限制,就是子类方法声明抛出的异常类型应该是父类方法声明抛出的异常类型的子类或相同,并且子类方法声明抛出的异常不允许比父类方法声明抛出的异常多
import java.io.*;
public class OverrideThrows
{
public void test() throws IOException
{
var fis = new FileInputStream("a.txt");
}
}
class Sub extends OverrideThrows
{
// 子类方法声明抛出了比父类方法更大的异常
// 所以下面方法出错
public void test() throws Exception
{
}
}
Checked异常有利有弊,增加了编程的复杂程度,而且受到重写方法时候的各种限制,但也存在好处能够在编译的时候就提醒开发者处理异常