四、异常的体系结构
Java 内置了丰富的异常体系, 用来表示不同情况下的异常.
下图表示 Java 内置的异常类之间的继承关系
顶层类 Throwable
派生出两个重要的子类, Error
和 Exception
其中 Error
指的是 Java 运行时内部错误和资源耗尽错误. 应用程序不抛出此类异常. 这种内部错误一旦出现,
除了告知用户并使程序终止之外, 再无能为力. 这种情况很少出现.
Exception
是我们程序猿所使用的异常类的父类.
其中 Exception
有一个子类称为 RuntimeException
, 这里面又派生出很多我们常见的异常类
NullPointerException , IndexOutOfBoundsException 等.
Java语言规范将派生于 Error
类或 RuntimeException
类的所有异常称为 非受查异常, 所有的其他异常称为 受查异常.
如果一段代码可能抛出受查异常
,必须显式处理
受查异常与非受查异常
Java语言规范将派生于 Error 类或 RuntimeException 类的所有异常称为非受查异常, 所有的其他异常称为受查异常。如果一段代码可能抛出 受查异常, 那么必须显式进行处理
如 FileNotFoundException 这样的异常就是受查异常,如果不显式处理, 编译无法通过,显式处理的方式有两种:
1.使用 try catch 包裹起来
因为在输入给sc时可能会出错,因此可以用try catch捕捉,此处虽然运行时可能会报错,但是会编译通过。这就是处理异常的好处。
2.在方法上加上异常说明, 相当于将处理动作交给上级调用者
使用throws说明异常,则不需要在readFile方法内部使用try catch捕捉异常。如果main方法没有使用try catch捕捉异常则交给JVM处理,否则是自己捕捉异常。
五、自定义异常类
Java 中虽然已经内置了丰富的异常类, 但是我们实际场景中可能还有一些情况需要我们对异常类进行扩展, 创建符合我们实际情况的异常
注意:
- 自定义异常类继承Exception类默认是受查异常
- 继承RuntimeException类默认是非受查异常。
用户登录代码实例
我们的想法是将自定义一个用户登录错误异常
此处一个异常类继承Exception还是RuntimeException的意义:
我们来举个例子:
假设自定义异常类继承的都是RuntimeException,则此处编译时不会报错,因为继承RuntimeException是非受查异常,则在运行时才会报错。
代码1:
假设自定义异常类继承的都是Exception,则默认自定义异常类为受查异常,再用上面的代码,只将自定义继承改为Exception。则编译时期就会报错。
因为受查异常要用两种显示的方式进行处理,要不用try catch语句处理,要不抛出异常用throw和throws成对处理。
对于为何自定义一个异常类需要在构造方法中调用父类的构造方法。是因为我们可以在throw new NameException();时能够在括号中说明错的原因。而输入错的原因时又是一个字符串。我们在看Exception异常类的源码时,可以看到它也是继承了Throwable类。而其中也调用了构造方法。我们也已经知道了一个子类的构造方法是默认一个不带参数的调用父类的构造方法的。因此一切都能说通了。
注意事项:
自定义异常通常会继承自 Exception 或者 RuntimeException
继承自 Exception 的异常默认是受查异常
继承自 RuntimeException 的异常默认是非受查异常.