异常
异常:在程序运行过程中,出现的不正常情况叫做异常
注意:
1.相同的代码在运行的时候,根据输入的参数或者操作的不同有可能会发生异常,有可能不会发生异常,应该在写代码的过程中尽可能的保证代码的正确性,不要到处都是bug
2.如果要解决代码中出现的异常,需要添加非常复杂的代码逻辑来进行判断,会使代码变得非常臃肿,不利于维护,因此推荐使用异常机制来处理程序运行过程中出现的异常
3.程序运行过程中如果出现了问题,会导致后面的代码无法正常执行,而使用异常机制之后,可以对异常情况进行处理,同时后续的代码会继续执行,不会中断整个程序
4.在异常的处理过程中,不要知识简单的输出错误,要尽可能的将详细的异常信息进行输出
使用e.printStackTrace():打印异常的堆栈信息,可以从异常信息的最后一行开始追踪,寻找自己编写的java类
处理异常的关键字:
try、catch、finally、throw、throws
常见的异常:
异常处理的方式:
1.捕获异常:
try{代码逻辑}catch(Exception e){异常处理逻辑}
try{代码逻辑}catch(具体的异常Exception e){异常处理逻辑}catch(具体的异常Exception e)
可以针对每一种具体的异常做相应的更丰富的处理
注意:当使用多重的catch的时候一定要注意相关异常的顺序,将子类放在最前面的catch,父类放在后面的catch
执行过程中可能存在的情况:
①正常执行,只执行try中的代码
②遇到异常情况,会处理try中异常代码之前的逻辑,后面的逻辑不会执行,最后会执行catch中的代码
③使用多重catch的时候会遇到异常子类不匹配的情况,此时依然会报错,因此建议在catch的最后将所有异常的父类包含进去
在程序运行过程中,如果处理异常的部分,包含finally的 处理,无论代码是否发生异常,finally的代码总会执行。
try{代码逻辑}catch(Exception e){异常处理逻辑}finally{代码逻辑}
finally包含哪些处理逻辑?
1.IO流的关闭操作一般设置在finally中
2.数据库的连接关闭操作设置在finally中
try-catch-finally的三种返回值情况:
1 第一种: 2 public class tryCatchFinally { 3 public static void main(String[] args) { 4 System.out.println(test()); 5 } 6 7 private static int test(){ 8 int num = 10; 9 try { 10 System.out.println("try"); 11 return num += 80; 12 }catch(Exception e){ 13 System.out.println("error"); 14 }finally { 15 if(num > 20){ 16 System.out.println("num > 20 :" + num); 17 } 18 System.out.println("finally"); 19 } 20 return num; 21 } 22 } 23 输出结果: 24 try 25 num > 20 :90 26 finally 27 90 28 分析:显然“return num += 80”被拆分成了“num = num+80”和“return num”两个语句,线执行try中的“num = num+80”语句,将其保存起来,在try中的“return num”执行前,先将finally中的语句执行完,而后再将90返回。
1 第二种: 2 public class tryCatchFinally { 3 public static void main(String[] args) { 4 System.out.println(test()); 5 } 6 7 private static int test(){ 8 int num = 10; 9 try { 10 System.out.println("try"); 11 return num += 80; 12 }catch(Exception e){ 13 System.out.println("error"); 14 }finally { 15 if(num > 20){ 16 System.out.println("num > 20 :" + num); 17 } 18 System.out.println("finally"); 19 num = 100; 20 return num; 21 } 22 } 23 } 24 输出结果: 25 try 26 num > 20 :90 27 finally 28 100 29 分析:try中的return语句同样被拆分了,finally中的return语句先于try中的return语句执行,因而try中的return被”覆盖“掉了,不再执行。
1 第三种: 2 public class tryCatchFinally { 3 public static void main(String[] args) { 4 System.out.println(test()); 5 } 6 7 private static int test(){ 8 int num = 10; 9 try { 10 System.out.println("try"); 11 return num; 12 }catch(Exception e){ 13 System.out.println("error"); 14 }finally { 15 if(num > 20){ 16 System.out.println("num > 20 :" + num); 17 } 18 System.out.println("finally"); 19 num = 100; 20 } 21 return num; 22 } 23 } 24 输出结果: 25 try 26 finally 27 10 28 分析:虽然在finally中改变了返回值num,但因为finally中没有return该num的值,因此在执行完finally中的语句后,test()函数会得到try中返回的num的值,而try中的num的值依然是程序进入finally代码块前保留下来的值,因此得到的返回值为10。
1 第四种: 2 public class tryCatchFinally { 3 public static void main(String[] args) { 4 System.out.println(test().num); 5 } 6 7 private static Num test(){ 8 Num number = new Num(); 9 try { 10 System.out.println("try"); 11 return number; 12 }catch(Exception e){ 13 System.out.println("error"); 14 }finally { 15 if(number.num > 20){ 16 System.out.println("number.num > 20 :" + number.num); 17 } 18 System.out.println("finally"); 19 number.num = 100; 20 } 21 return number; 22 } 23 } 24 25 class Num{ 26 public int num = 10; 27 } 28 输出结果: 29 try 30 finally 31 100 32 分析:从结果中可以看出,同样是在finally中改变了返回值num的值,在情况三中,并没有被try中的return返回(test()方法得到的不是100),但在这里却被try中的return语句返回了。
总结: try语句在返回前,将其他所有的操作执行完,保留好要返回的值,而后转入执行finally中的语句,而后分以下三种情况: 情况一:如果finally中有return语句,则会将try中的return语句覆盖掉,直接执行finally中的return语句,得到返回值,这样便无法得到try之前保留好的返回值 情况二:如果finally中没有return语句,也没有改变返回值,则执行完finally语句后,会接着执行try中的return语句,返回之前保留的值 情况三:如果finally中没有return语句,但是改变了要返回的值,这里有点类似于引用传递和值传递的区别。分以下两种情况: 1.如果return的数据是基本数据类型或文本字符串,则在finally中对该基本数据的改变不起作用,try中的return语句依然会返回进入finally块之前保留的值 2.如果return的数据是引用数据类型,而在finally中对该引用数据类型的属性值的改变起作用,try中的return语句返回的就是在finally中改变后的该属性的值
2.声明异常 (throws)
在异常情况出现的时候可以使用try-catch-finally的方式对异常进行处理,除此之外,可以将异常向外抛出,由外部进行处理
①在方法调用过程中给可能出现n多个方法之间的调用,此时假如每个方法中都包含了异常情况,那么就需要在每个方法中都进行try-catch;另外一种比较简单的方法就是在方法最外层调用处理一次即可
使用throws的方法,对所有执行过程中的所有方法出现的异常进行统一集中处理
②如何判断是使用throws还是使用try-catch?
最稳妥的方式是在每个方法中都进行异常的处理
偷懒的方式是判断在整个调用过程中外层的调用方法是否有对异常的处理,如果有,直接使用throws
3.抛出异常(throw)
在方法后添加throws Exception,在方法中使用throw new Exception("xxxxxxx")
4.自定义异常
步骤:定义一个类继承Exception类,自定义实现构造方法,使用的时候throw new Exception
1 public class NewException extends Exception { 2 3 public NewException(){ 4 System.out.println("自定义异常"); 5 } 6 7 public NewException(String str){ 8 System.out.println(str); 9 } 10 } 11 其它类中进行调用: 12 throw new NewException();
异常的分类:
所有异常的父类是throwable
throwable下面分为error(系统级的异常,代码无法解决)和exception
exception分为checked异常(程序必须处理)和运行时异常