1.什么是异常
异常:程序在执行过程中发生的不正常行为
例如:
publicclassTest { publicstaticvoidmain(String[] args) { inta=1/0; System.out.println(a); } }
Java中有许多不同类型的异常,例如算数异常(ArithmeticException)、空指针异常(NullPointerException)、类型转换异常(ClassCastException)
当出现异常时,我们要设法处理异常,使程序能够继续正常运行
2.异常的处理
2.1 异常的抛出
(1)什么是异常的抛出
当程序中出现异常时,将错误信息告知调用者。
(2)如何抛出异常
使用 throw 关键字,抛出一个指定的异常对象,将错误信息告知调用者
使用格式:
thrownew异常类名( 参数 );
例如
publicclassTest { publicstaticvoidmain(String[] args) { intret=divide(3,0); System.out.println(ret); } publicstaticintdivide(inta, intb){ //判断除数是否为0,若为0,抛出异常if(b==0){ thrownewArithmeticException("除数为0,无法计算!"); } returna/b; } }
运行结果
注:
1. throw关键字必须在方法内部使用
2. 抛出的对象必须是 Exception 或者 Exception的子类对象
3. 如果抛出的是 RunTimeException 或者 RunTimeException 的子类,则可以不用处理,直接交给JVM来处理
4. 如果抛出的是编译时异常,用户必须处理,否则无法通过编译
5.异常一旦抛出,其后的代码不再执行
2.2 异常的捕获
对出现的异常进行捕捉,主要有两种 异常声明throws 和 try-catch捕获处理
(1)异常声明throws
当方法中抛出编译时异常,用户不想处理异常时,就可以借助throws将异常抛给方法的调用者来处理。即自己不处理异常,将异常上抛(抛给调用者),由调用者对这个异常进行处理,若调用者不处理,继续上抛,最终抛给main方法,main方法再上抛,抛给JVM处理,处理结果则是Java程序终止。
throws处在方法声明时参数列表之后,可抛出多个异常类型
使用格式
修饰符返回值类型方法名( 参数列表 ) throws异常类型1, 异常类型2, ...{ }
例如
publicstaticintgetNumber(int[] arr, inti) throwsNullPointerException, ArithmeticException{ if(arr==null){ thrownewNullPointerException(); } if(i>=arr.length){ thrownewArrayIndexOutOfBoundsException(); } returnarr[i]; }
将光标放在抛出异常方法上,alt+ 回车,即可快速抛出异常
注:
1.throws必须处在方法的参数列表之后
2. 声明的异常必须是 Exception 或者 Exception 的子类
3.方法内部如果抛出多个异常,throws之后必须跟多个异常类型,异常类型之间用逗号隔开,若抛出的多个异常类型具有父子关系,则直接声明父类即可
(2)try-cathc捕获处理
throws只是将异常抛给调用者,要真正处理异常,则需使用try-catch处理异常
使用格式
try{ //可能出现异常的代码} catch(异常类型e){ //若try中的代码抛出异常,此处catch捕获的异常类型与try中抛出的异常类型一致,或是try中抛出异常的基类,就会捕捉异常//对异常进行处理,处理完成后,跳出try-catch结果,执行后续代码} catch(异常类型e){ //对异常进行处理}finally{ //一定会被执行的代码} //后续代码//当异常被捕获到(即异常被处理了),后续的代码就会执行//当异常未被捕获到(异常未被处理),后续的代码不会被执行
注:
1.try块内抛出异常位置之后的代码将不会被执行
2.抛出异常类型与catch异常类型不匹配,即异常未被成功捕获,就不会被处理,继续向外抛,直到JVM收到后中断程序,异常是按照类型来捕获的
后续代码的执行
publicclassTest { publicstaticvoidmain(String[] args) { try{ int[] arr= {0,1,2,3}; System.out.println(arr[10]); }catch (NullPointerExceptione){ e.printStackTrace(); }catch (ArrayIndexOutOfBoundsExceptione){ e.printStackTrace(); }finally { System.out.println("*************"); } System.out.println("aaa"); } }
e.printStackTrace():打印异常追踪的堆栈信息
运行结果
此时异常类型被捕获,后续代码被执行
publicclassTest { publicstaticvoidmain(String[] args) { try{ int[] arr= {0,1,2,3}; System.out.println(arr[10]); }catch (NullPointerExceptione){ e.printStackTrace(); }finally { System.out.println("*************"); } System.out.println("aaa"); } }
运行结果
此时异常与catch异常类型不匹配,未被捕获到,即异常未被捕获成功,后续代码不再执行,仅finally中代码执行
try中可能出现多种异常,此时用多个catch对异常进行捕获
publicclassTest { publicstaticvoidmain(String[] args) { try{ inta=1/0; int[] arr= {0,1,2,3}; System.out.println(arr[10]); }catch (NullPointerExceptione){ e.printStackTrace(); }catch (ArrayIndexOutOfBoundsExceptione){ e.printStackTrace(); }catch (Exceptione){ e.printStackTrace(); }finally { System.out.println("*************"); } } }
当异类之间具有父子关系时,先捕获子类异常,后捕获父类异常,否则会出现语法错误
若多个异常的处理方式是相同的,也可以写成
catch (ArrayIndexOutOfBoundsException|NullPointerExceptione){ e.printStackTrace(); }
finally的使用
finally不是必须存在的,当没有需要必须执行的代码时,可不使用finally
而有的特定的代码,程序是否发生异常,都需要执行,如对打开的资源进行回收,此时就可使用finally解决这个问题
importjava.util.InputMismatchException; importjava.util.Scanner; publicclassTest { publicstaticvoidmain(String[] args) { Scannersc=null; try{ sc=newScanner(System.in); inta=sc.nextInt(); System.out.println(a); }catch (InputMismatchExceptione){ e.printStackTrace(); }finally { if(sc!=null){ sc.close(); } } } }
由于finally中的代码一定会执行的,一般在finally中进行一些资源清理的扫尾工作。
publicclassTest { publicstaticvoidmain(String[] args) { System.out.println(fun()); } publicstaticintfun(){ try{ return1; }finally { return10; } } }
运行结果
由于finally执行是在方法返回之前,如果try或者catch中有return语句,finally会在该语句之前执行,若finally中也有return语句,那么则执行finally中语句,而不会执行try或者catch中有return语句
因此,不建议在finally中使用return语句
3. 自定义异常类
Java中虽然有许多异常类,但是并不能完全满足我们的需求,此时就需要我们依据实际情况,自定义异常类
自定义异常通常会继承自 Exception 或 RuntimeException,继承 Exception 的异常默认是受查异常,继承自 RuntimeException 的异常默认是非受查异常
3.1 如何定义异常类
1.自定义一个异常类,继承自 Exception 或 RuntimeException
2.实现一个带有String类型参数的构造方法,参数表示出现异常的原因
我们以用户登录为例
publicclassLogin { privatestaticStringuserName="admin"; privatestaticStringpassword="111"; publicstaticvoidlogin(Stringname, Stringword) throwsUserNameException,PassWordException{ if(!userName.equals(name)){ thrownewUserNameException("用户名错误!"); } if(!password.equals(word)){ thrownewPassWordException("密码错误!"); } System.out.println("登录成功!"); } publicstaticvoidmain(String[] args) { try{ login("admin","aaa"); } catch (UserNameExceptione){ e.printStackTrace(); } catch (PassWordExceptione){ e.printStackTrace(); } } } //用户名异常classUserNameExceptionextendsException{ publicUserNameException(Stringmessage){ super(message); } } //登录密码异常classPassWordExceptionextendsException{ publicPassWordException(Stringmessage){ super(message); } }
运行结果