1.异常概述
异常,又称为例外,是指不可预知的非正常的情况,例如:正常开车突然路口窜出一条狗来,或者正常上下班的路上,某个街角偶遇了爱情,或者在每天晨跑的小树林遭遇了歹徒。这些突发的情况的发生是不可预知的,where,when…,但是如果处理好了,美好的生活不受影响,可以继续,如果处理不好,可能就“挂”了。
Java语言将程序执行中发生的不正常情况称为“异常”,异常是一种对程序运行过程中发生错误时进行通知的机制。如:网络连接失败、用户输入错误或打开文件失败等。
注意:
- 语法错误不属于异常,这种情况编译不通过,无法运行;
- 逻辑错误不属于异常,这种情况属于BUG,必须修正;
2.异常的类型和整体结构
1、异常系列的超父类:java.lang.Throwable
(1)只有它或它子类的对象,才能被JVM或throw语句“抛”出
(2)也只有它或它子类的对象,才能被catch“捕获”
2、Throwable有两个直接子类
(1)Error:用于指示合理的应用程序不应该试图捕获的严重问题。这些错误表示故障发生于虚拟机自身、或者发生在虚拟机试图执行应用时,如Java虚拟机运行错误(Virtual MachineError)、类定义错误(NoClassDefFoundError)等。这些错误是不可查的,因为它们在应用程序的控制和处理能力之 外,而且绝大多数是程序运行时不允许出现的状况。对于设计合理的应用程序来说,即使确实发生了错误,本质上也不应该试图去处理它所引起的异常状况。在 Java中,错误通过Error的子类描述。
(2)Exception: 一般的异常,可以通过判断、检验进行避免,或者使用try…catch进行处理
- 运行时异常(uncheckedException):
它是RuntimeException或它子类的对象。例如:数组下标越界异常ArrayIndexOutOfBoundsException,空指针异NullPointerException,类型转换异常ClassCastException等等。
这种类型的异常,编译器不会提醒你,要进行throws或try…catch进行处理,但是运行时可能导致崩溃。
- 编译时异常(checkedException):
异常除了运行时异常以外的都是编译时异常。例如:FileNotFoundException(文件找不到异常)、IOException(输入输出异常)、SQLException(数据库sql语句执行异常)。
这种类型的异常,编译器是强制要求你,throws或try…catch进行处理,否则编译不通过。
3.异常的处理
1、在当前方法中处理:try…catch…finally
//形式
try{
可能发生异常的代码
}catch(异常类型 异常名e){
处理异常的代码(一般都是打印异常的信息的语句)
}catch(异常类型 异常名e){
处理异常的代码(一般都是打印异常的信息的语句)
}。。。
finally{
无论try中是否有异常,也不管catch是否可以捕获异常,也不管try和catch中是不是有return,都要执行的部分
}
//如果try中的代码没有异常,那么try中的代码会正常执行,catch部分就不执行,finally中依然会执行
//如果try中的代码有异常,那么try中发生异常的代码语句的后面就不执行了,找对应的匹配的catch分支执行,finally中会执行
示例:
public class Test {
public static void main(String[] args) {
try{
System.out.println(1/0);
}catch (ArithmeticException e){
System.out.println("分母不能为0");
}
finally{
System.out.println("程序结束");
}
}
}
//输出:分母不能为0 程序结束
2、显式声明抛出异常(throws)
如果一个方法出现Checked Exception,但是并不能确定如何处理这种异常或者不立刻处理它,则此方法应显示地声明抛出异常,表明该方法将不对这些异常进行处理,而由该方法的调用者负责处理。
在方法声明中用throws语句可以声明抛出异常的列表,throws后面的异常类型可以是方法中产生的异常类型,也可以是它的父类。如果一个方法抛出多个受检异常,就必须在方法的签名中列出所有的异常,之间以逗号隔开。
语法格式:
【修饰符】 返回值类型 方法名(【形参列表】) throws 异常列表{
}
例:
public class Test02 {
public static void main(String[] args) {
arrTest();
}
public static void arrTest() throws ArrayIndexOutOfBoundsException{
int[] arr = {1,2,3};
arr[4]=10;
}
}
4.手动抛出异常(throw)
Java异常类对象除在程序执行过程中出现异常时由系统自动生成并抛出,也可以根据需要手动创建并抛出。可以抛出的异常必须是Throwable或其子类的实例。
首先要创建异常类对象,然后通过throw语句实现抛出操作,提交给Java运行环境。
语法格式:
throw 异常对象;
//例如:
throw new AccountException("xxx");
示例:
public class Test01 {
public static void check(String usrname ,String passwd) {
if(usrname==null||"".equals(usrname.trim())){
throw new RuntimeException("用户名不能为空");
}
if(passwd==null||"".equals(passwd.trim())){
throw new RuntimeException("密码不能为空");
}
}
}
5.自定义异常
在程序中,可能会遇到任何标准异常类都没能充分的描述清楚的问题,这种情况下可以创建自己的异常类。
- 从Exception类或者它的子类派生一个子类即可
- 习惯上,自定义异常类应该包含2个构造器:一个是无参构造,另一个是带有详细信息的构造器
- 自定义的异常只能通过throw抛出。
- 自定义异常最重要的是异常类的名字,当异常出现时,可以根据名字判断异常类型。
示例:
public class Test01 {
public static void main(String[] args) {
check("","");//抛出自定义异常
}
public static void check(String usrname ,String passwd){
if(usrname==null||"".equals(usrname.trim())){
throw new MyException("用户名不能为空");
}
if(passwd==null||"".equals(passwd.trim())){
throw new MyException("密码不能为空");
}
}
}
class MyException extends RuntimeException {
public MyException() {
}
public MyException(String message) {
super(message);
}
}
6.异常的几个方法
(1)e.printStackTrace():打印异常对象的详细信息,包括异常类型,message,堆栈跟踪信息。这个对于调试,或者日志跟踪是非常有用的
(2)e.getMessage():只是获取异常的message信息
关于异常信息的打印:
用System.err打印和用e.printStackTrace()都是会标记红色的突出。
用System.out打印,当成普通信息打印。
这两个打印是两个独立的线程,顺序是不能精确控制的。
补充:重写方法对throws异常的要求
重写方法不能抛出比被重写方法范围更大的异常类型。在多态的情况下,对重写方法的调用–异常的捕获按父类声明的异常处理。即
- 父类被重写的方法没有声明抛出checked受检异常,那么重写的方法也不能声明抛出异常
- 子类重写方法声明抛出的异常的类型和父类被重写的方法声明抛出异常类型一致
- 子类重写方法声明抛出的异常的类型是父类被重写的方法声明抛出异常的子类
- 子类重写方法可以在方法内部处理异常,而不声明抛出异常
示例:
class A{
public void method()throws IOException{}
}
class B extends A{
public void method(){}
}
class C extends A{
public void method() throws FileNotFoundException{}
}
class D extends A{
public void method() throws IOException,FileNotFoundException{}
}
class E extends A{
public void method() throws IOException,RuntimeException{}
}