(1)异常和错误
异常(Exception):不正常的事件,会中断程序,在运行中发生的意外,程序本身可以处理,防止程序中断;程序中会捕获的异常信息,并告诫用程序员,不要求程序必须对它做处理.catch完之后不作处理.
错误(Error):程序本身无法处理的.比如跟操作系统不兼容的问题.设计内存问题.,应用程序不应该抛出这类异常信息,这种错误程序员无法处理。
(2)异常的分类;
下图表示了异常类之间的关系.
所有的异常类的父类都是Exception,它有两大分支:检查异常类和非检查异常类(RuntimeException),
又称是编译器异常)和运行期异常(比如)。
编译器异常就是在编译器中敲代码时候的错误提示,如果不修改就没法运行这个程序。
运行期异常顾名思义就是程序编译通过,但是在输出时候发生异常,比如是在控制台输入时敲错了数字,导致进行运算时候发生错误;如进行除法运算,输入了0;
Exception一个重要的分支是runtimeexception,它是描述编程产生的错误,这种异常通常由JVM自动捕获并抛出,说明这段代码有问题.下面就要说明捕获到异常之后怎么处理.
(3)异常的处理;
将意外进行处理的语句;
1.Try-catch语句;
try-catch的语法格式如下:
Try { //可能发生的异常代码 } Catch { //捕捉到异常之后的对它的处理; }
(示例代码如下)
1 public class exceptiondemo { 2 3 public static void main(String[] args) { 4 5 int a=0; 6 int b=0; 7 try{ 8 9 System.out.println(a/b); 10 11 } 12 catch(Exception e) 13 { 14 15 e.printStackTrace(); 16 //获取异常的堆栈信息 17 //可以自己定义捕捉异常之后输出的提示内容,让程序员更加明白发生了的什么异常; 18 System.out.println("除法运算出现异常"); 19 20 } 21 22 System.out.println("finish!"); 23 24 } 25 }
运行结果;
除法运算出现异常
finish!
java.lang.ArithmeticException: / by zero
at day23_1027.exceptiondemo.main(exceptiondemo.java:11)
通过上面的代码以及运行结果发现:上面可以发现,catch捕捉到异常,但是并不会影响后面的语句执行,而如果没有用trycatch语句来获取异常信息,后面的代码并不会执行。
但是在程序中Try会抛出很多种类的异常(空指针,或者是数学运算的问题都有可能),这个时候不建议只用一个Exception来捕获各种异常,当有多个try catch语句的时候,程序会按顺序执行,这个时候父类异常Exception应该放在后面,子类的错误放在前面,当抛出的异常都不属于子类的异常,就由父类来捕获处理.就是说先小后大,先子类后父类.
public static void main(String[] args) { int a=2; int b=1; String c=null; try{ System.out.println("a/b="+a/b); int index=c.indexOf(0); System.out.println(index); } catch(ArithmeticException e) { System.out.println("除数不能为0!!"); } catch(NullPointerException e) { System.out.println("检测到空指针异常!!"); } catch(Exception e) { System.out.println("检测到不知名异常!!"); } System.out.println("风雨不改还是运行完了"); } }
运行结果:
a/b=2
检测到空指针异常!!
风雨不改还是运行完了
当父类异常放在前面的时候,会有如下显示,可见在编译器中两个子类都有错误提示出现.(可在编译器中复制错误代码示例看编译器报错的提示)
一般一段代码可能有多种异常抛出时,不要把父类的异常放在前面。
ry{ System.out.println("a/b="+a/b); int index=c.indexOf(0); System.out.println(index); } catch(Exception e) { System.out.println("检测到不知名异常!!"); } catch(ArithmeticException e) { System.out.println("除数不能为0!!"); } catch(NullPointerException e) { System.out.println("检测到空指针异常!!"); }
最后提示一点:
一个catch只会处理一个try的信息,不可一个try同时匹配到多个catch信息.(放在同一个try里面,不能同时检测到空指针同时又检测到除数不能为0),不同功能的代码就放在不同的try里面.
(2)Try-catch-finally 语句
在java中,Finally的作用是程序不管什么情况都会执行里面的代码,不管是否执行catch语句;对于大多数程序都是这样子。
但是也有唯一的情况————————
System.exit(1) //该语句意思是直接退出JAVA虚拟机
若程序中出现该语句,并且在finally语句之前,那么finally不会执行,这也是finally不执行的唯一情况;
下面通过实例来演示finally的作用:
public class exceptiondemo2 { public static void main(String[] args) { Scanner sc=new Scanner(System.in); int a=1; int b=0; String c=null; try{ System.out.println("a/b="+a/b); int index=c.indexOf(0); System.out.println(index); } catch(ArithmeticException e) { System.out.println("除数不能为0!!"); } finally{ System.out.println("(这是finally语句块)这是一定要执行的!!"); } System.out.println("程序执行完了!!"); } }
(3)try-catch-finally 语句若try中&catch有returns的情况
完整try-catch-finally 若try中&catch有returns语句且先不将此返回给调用者,等finally执行完毕后返回return。
try...catch...finally...三个语句块中如果有return语句的执行顺序。
finally中有return用finally.return代替,顺序为:
“try语句 -> catch -> finally -> finally.return -> catch.return -> try.return”任何阶段的return被执行,则整个语句块结束。
二:小总结
(1)异常处理的流程:
try { //执行的代码,其中可能有异常。一旦发现异常,则立即跳到catch执行。否则不会执行catch里面的内容 }
catch { //除非try里面执行代码发生了异常,否则这里的代码不会执行 }
finally { //不管什么情况都会执行,包括try catch 里面用了return ,可以理解为只要执行了try或者catch,就一定会执行 finally }
所以通常都会用finally语句来进行资源的释放;比如涉及到数据库的使用好关闭,出现了异常立马关闭数据库.
(2)try-catch实际应用
对于不确定的代码,可以加上try-catch处理潜在的异常;
尽量去处理异常,最好不要只是简单的调用printStackTrace()去打印输出; 比如是在打印输出异常同时最好加点操作,比如是业务回滚;
具体怎么去处理异常,就要根据不同的业务需求和异常类型去决定,
有网络连接和连接数据库的历程,尽量去添加finally语句去释放占用的资源,在程序发生异常或者执行结束之后自动清理内存资源,减少系统负担。