异常层次结构

时间:2020-01-09 10:35:58  来源:igfitidea点击:

在Java和C例外中,可以将其分类为层次结构。通过使一个(或者多个)异常扩展另一个异常来创建层次结构。第一个异常成为第二个异常的子类。在Java中,FileNotFoundException是IOException的子类。这是自定义异常在Java代码中的外观:

public class MyException extends Exception{
    //constructors etc.
}

如我们所见,它没有太多的意义。异常层次结构的优点是,如果我们决定在层次结构中捕获(使用try-catch)某个异常,那么我们也将自动捕获该异常的所有子类。换句话说,我们将从该特定异常中捕获所有异常,并从层次结构中捕获所有异常。在带有FileNotFoundException的示例中,如果捕获到FileExceptionFoundException的超类IOException,则还将捕获FileNotFoundException。

多个捕获块

我们可能已经知道,同一个try块可能有多个catch块。如果try块中的代码抛出不止一种类型的异常,通常就是这种情况。但是,如果在try块中引发的所有异常都是相同类型或者该类型的子类,则也可以使用多个catch块。此代码说明:

try{
    //call some methods that throw IOException's
} catch (FileNotFoundException e){
} catch (IOException e){
}

请记住,第一个catch块引发的异常匹配将处理该异常。在此示例中,除FileNotFoundException外,所有IOException都由catch(IOException e)处理。 FileNotFoundException是IOException的子类,这一事实使我们可以选择将所有IOException视为相同,还是单独捕获某些IOExceptions子类,如上面的代码示例所述。如果删除catch(FileNotFoundException e)块,则由于catch(IOException e)块将捕获任何FileNotFoundException,因为FileNotFoundException是IOException的子类。

抛出子句

如果一个方法可以抛出某个异常A或者A的任何子类(Asub),则在方法声明中声明该方法抛出A就足够了。然后也可以从该方法中抛出A的子类。这是一个例子:

public void doSomething() throws IOException{
}

即使实际上不需要,也可以在方法的throws子句中声明子类。它可以使代码更易于阅读和理解,以供下一个开发人员查看。这是一个例子:

public void doSomething() throws IOException, FileNotFoundException{
}

只要还声明了任何已声明异常的超类,就不会对包含子类的抛出的代码产生任何影响。在上面的示例中,当还声明了IOException时,声明抛出FileNotFoundException并没有实际效果。当我们捕获IOException时,我们还将捕获FileNotFoundException。即使仅声明超类被抛出,仍可以使用各自的catch块来处理这两个异常。

设计异常层次结构

在为API或者应用程序设计异常层次结构时,最好为该API或者应用程序创建基本异常。例如,在Persister先生的Java Persistence / ORM API中,基本异常称为PersistenceException。此基本异常可以捕获和处理Persister先生在同一catch块中引发的所有异常。

如果我们需要对抛出的异常进行更细粒度的处理(例如,因为我们认为异常的处理方式可能不同),请添加新的异常作为API或者应用程序基础异常的子类。这样,用户可以选择捕获特定异常,还是仅捕获基本异常。在Persister先生中,我们可以添加ConnectionOpenException,QueryException,UpdateException,CommitException和ConnectionCloseException作为PersistenceException的子类。如果Persister先生的用户想要以不同于QueryException或者ConnectionCloseException的方式处理ConnectionOpenException,则他们可以捕获这些异常并以不同的方式处理它们。如果没有,用户可以捕获PersistenceException并统一处理所有异常。

我们可以通过向层次结构添加更多级别来进一步细分例外。例如,我们可能想要区分由于数据库URL错误而引发的异常与因数据库未运行而引发的异常。在那种情况下,我们可以创建两个名为DatabaseURLException和DatabaseNotRespondingException的异常,它们都扩展了ConnectionOpenException。然后,用户可以捕获这两个不同的异常并对它们做出不同的响应。在本文中,我们看到可以通过对异常类进行子类化来创建异常层次结构。为API或者应用程序创建一个基本异常,并让所有其他异常成为该基本异常的子类是一个好主意。单独的子类可以(但不是必须)以不同的方式捕获和处理这些单独的异常。我们应该只为实际上可以以不同方式处理的错误创建单独的例外。