当前位置:   article > 正文

《第一行代码Android2版》笔记八:catch(Exception e) 异常捕捉详解_catch (exception e){}

catch (exception e){}

一、理论讲解

作为一个面向对象编程的程序员对于 下面的一句一定非常熟悉: 

  1. try
  2.   {
  3.   // 代码块
  4.   }
  5.   catch(Exception e)
  6.   {
  7.   // 异常处理
  8.   }
  9.   finally
  10.   {
  11.   // 清理工作
  12.   }

  就是面向对象中最最常见的异常处理程序,而且甚至我们会莫名其妙的被编译器要求加上这个模块,甚至我们自己也不知道捕捉到异常该怎么处理…

  为什么要有异常

  其实这个问题不用多说,程序员都知道,简单总结为一句话:就是为了增强程序健壮性呗,比如下面的代码: 

  1. Class DenominatorZeroException extends Exception{}
  2.   public double division(int numerator,int denominator) throws DenominatorZeroException
  3.   {
  4.   double result;
  5.   try
  6.   {
  7.   if(denominator == 0)
  8.   throw new DenominatorZeroException();
  9.   else
  10.   result = numerator/denominator;
  11.   }
  12.   catch(DenominatorZeroException e)
  13.   {
  14.   e.printStackTrace();
  15.   return -1;
  16.   }
  17.   return result;

 

  这段代码很简单,就是为了预防除法中发生分母为0的情况,为了增强代码的健壮性,我声明了一个自定义的异常名为:DenominatorZeroException,这个异常继承自所有异常的根类Exception,当代码发现分母为0的时候就将new一个异常然后跑出,当catch捕捉到这个异常后,则返回一个预先定义好的标志-1;否则正常返回除法结果。

  其实在Java语言中,按照我自己看书和平时编程的理解,异常的作用可以概括为以下两点:

  1、增强程序健壮性。

            当遇到异常(为什么叫异常而不是错误,就是说在当前编程环境下,出现这种情况很奇怪,不正常,无法解决)我们可以捕获它,然后有两种选择:一是就像上面的代码一样,我们知道异常的原因,然后进行相应的处理,这样并不会影响程序的正常执行;二是我们并不知道捕获这个异常该怎么处理,我们就可以利用Java的异常链可以将这个异常抛给上一级代码或者直接抛给控制台(就像上面的代码e.printStackTrace()打印出栈轨迹或者利用异常说明加在主函数入口处)。

  2、报告。

         Java程序员可能会发现当我们程序遇到bug停止的时候,所有报告的错误信息都是以异常的形式产生的,这样统一的形式使得程序员在编写程序时不必考虑如果程序运行出错怎么办,Java会做好的,出错会向你报告而且绝对不会遗漏(除了异常"吞咽",稍后说明),程序员就可以专心设计和实现自己的代码了。

二、扩展延申:throw关键字

  我们要将一个异常跑出就需要throw关键字,其实在某种程度上,我们可以将throw和return进行一个类比,因为当我们使用throw抛出异常时就会跳出当前的方法或者作用域,这与return是非常相似的。

       但是一定不能混淆,因为return关键字返回的"地点"一般就是主调函数处然而throw抛出异常,而捕获异常的这个"地点"可能距离现有函数的地址很远。  

  1. Class DenominatorZeroException extends Exception{}
  2.   Class AnotherException extends Exception
  3.   {
  4.   public AnotherException(String s){super(s);}
  5.   }
  6.   public double division(int numerator,int denominator) throws DenominatorZeroException, AnotherException
  7.   {
  8.   double result;
  9.   try
  10.   {
  11.   if(denominator == 0)
  12.   throw new DenominatorZeroException();
  13.   else
  14.   result = numerator/denominator;
  15.   }
  16.   catch(DenominatorZeroException e)
  17.   {
  18.   throw e;
  19.   /*或者*/
  20.   throw new RuntimeException(e);
  21.   /*或者*/
  22.   AnotherException ae = new AnotherException("from division");
  23.   ae.initCause(new DenominatorZeroException());
  24.   throw ae;
  25.   }
  26.   return result;
  27.   }

  还是上面除法的例子,我想做点说明:

  当我们在catch中捕获到一个异常不知道怎么处理时,可以利用throw直接再将这个异常抛出;

  同样我们也可以直接将这个异常抛给RuntimeException,让它直接抛出运行时异常(就是现实在控制台的错误信息);

  然而上面两种方式有一个问题就是当我们再次抛出异常时,我们最一开始发生异常的位置就会丢失,所以我们利用initCause将原先的异常加入,并且在异常信息中也添加了"from division"

备注:

        1、解释异常"吞噬",就是捕获了异常什么都不做,也不抛出,那么这样很危险,因为找不到错误信息了。

   2、异常说明throws

  我们在调用Java的库函数的时候肯定会遇到这种情况(尤其是IO操作的地方):就是调用了一个函数,然后编译器报错,给出的解决方案是要么加入try,catch块,要么就在主调函数的后面加上throws,并且后面跟上可能抛出的异常。这里后者就是所谓的异常说明。

  为什么要有异常说明:这主要是编写类的程序员要将方法可能会抛出的异常告知客户端程序员。

 

三、实例验证

1、

  1. package test.s;
  2. public class yichang {
  3.     
  4.     public static void main(String[] args) throws Exception{
  5.         try{
  6.             double a=aa();
  7.             System.out.println(a);
  8.         }catch(Exception e){
  9.             e.printStackTrace();
  10.         }
  11.     }
  12.     
  13.     public static double aa() throws Exception{
  14.         double b = 0;
  15.         try{
  16.             b=1/0;
  17.         }catch(Exception e){
  18.             throw new Exception(e.getMessage());
  19.         }
  20.         return b;
  21.     }
  22.  
  23. }

输出:
java.lang.Exception: / by zero
    at test.s.yichang.aa(yichang.java:18)
    at test.s.yichang.main(yichang.java:6)


说明:这算是比较正常的异常写法。aa()方法抛出异常,mian方法捕获异常,并打印出异常原因。

2,

  1. package test.s;
  2. public class yichang {
  3.     
  4.     public static void main(String[] args) throws Exception{
  5.         try{
  6.             double a=aa();
  7.             System.out.println(a);
  8.         }catch(Exception e){
  9.         }
  10.     }
  11.     
  12.     public static double aa() throws Exception{
  13.         double b = 0;
  14.         try{
  15.             b=1/0;
  16.         }catch(Exception e){
  17.             throw new Exception(e.getMessage());
  18.         }
  19.         return b;
  20.     }
  21.  
  22. }

没有输出;

说明:这个跟1的区别是main方法捕获aa传来的异常后没有将异常打印出来,所以没有任何输出。

3,

  1. package test.s;
  2. public class yichang {
  3.     
  4.     public static void main(String[] args) throws Exception{
  5.         try{
  6.             double a=aa();
  7.             System.out.println(a);
  8.         }catch(NullPointerException e){
  9.             e.printStackTrace();
  10.         }
  11.     }
  12.     
  13.     public static double aa() throws Exception{
  14.         double b = 0;
  15.         try{
  16.             b=1/0;
  17.         }catch(Exception e){
  18.             throw new Exception(e.getMessage());
  19.         }
  20.         return b;
  21.     }
  22.  
  23. }


输出:
Exception in thread "main" java.lang.Exception: / by zero
    at test.s.yichang.aa(yichang.java:18)
    at test.s.yichang.main(yichang.java:6)

说明:在主方法中的catch(nullPointerException e)是空指针异常。而aa()方法抛出来的异常是ArithmeticException,所以main方法虽然用try catch把aa()方法包裹起来,但是并没有捕获改异常。控制台打印的是java自己处理打印出来的异常。
效果跟下面的代码是一样的:也就是main方法中不用try catch

  1. package test.s;
  2. public class yichang {
  3.     
  4.     public static void main(String[] args) throws Exception{
  5.             double a=aa();
  6.             System.out.println(a);
  7.     }
  8.     
  9.     public static double aa() throws Exception{
  10.         double b = 0;
  11.         try{
  12.             b=1/0;
  13.         }catch(Exception e){
  14.             throw new Exception(e.getMessage());
  15.         }
  16.         return b;
  17.     }
  18. }

4,

  1. package test.s;
  2. public class yichang {
  3.     
  4.     public static void main(String[] args) throws Exception{
  5.         try{
  6.             double a=aa();
  7.             System.out.println(a);
  8.         }catch(NullPointerException e){
  9.             e.printStackTrace();
  10.         }
  11.     }
  12.     
  13.     public static double aa() throws Exception{
  14.         double b = 0;
  15.         try{
  16.             b=1/0;
  17.         }catch(NullPointerException e){
  18.             throw new NullPointerException(e.getMessage());
  19.         }
  20.         return b;
  21.     }
  22. }
  23.  

输出:

Exception in thread "main" java.lang.ArithmeticException: / by zero
    at test.s.yichang.aa(yichang.java:16)
    at test.s.yichang.main(yichang.java:6)

说明这种是catch(NullPointerException e),在aa方法中只能捕获空指针异常,但是b=1/0报的是算术异常,因此也是无法捕获的。使用debug跑程序会发现程序运到b=1/0就打印异常结束程序了。
因此同以下代码:

  1. package test.s;
  2. public class yichang {
  3.     
  4.     public static void main(String[] args){
  5.             double a=aa();
  6.             System.out.println(a);
  7.  
  8.     }
  9.     
  10.     public static double aa() {
  11.         double b = 0;
  12.             b=1/0;
  13.  
  14.         return b;
  15.     }
  16.  
  17. }

5, 

  1. package test.s;
  2.     public class yichang {
  3.         
  4.         public static void main(String[] args) throws Exception{
  5.             try{
  6.                 double a=aa();
  7.                 System.out.println(a);
  8.             }catch(NullPointerException e){
  9.                 e.printStackTrace();
  10.             }
  11.         }
  12.         
  13.         public static double aa() throws Exception{
  14.             double b = 0;
  15.             try{
  16.                 b=1/0;
  17.             }catch(ArithmeticException e){
  18.                 throw new ArithmeticException(e.getMessage());
  19.             }
  20.             return b;
  21.         }
  22.     
  23.     }

输出:

Exception in thread "main" java.lang.ArithmeticException: / by zero
    at test.s.yichang.aa(yichang.java:18)
    at test.s.yichang.main(yichang.java:6)


说明:这中情况也很明显了。aa方法中的try catch 能捕获异常,但是mian方法中的try catch不行
6,最准确的情况
  

  1.  package test.s;
  2.     public class yichang {
  3.         
  4.         public static void main(String[] args) throws Exception{
  5.             try{
  6.                 double a=aa();
  7.                 System.out.println(a);
  8.             }catch(ArithmeticException e){
  9.                 e.printStackTrace();
  10.             }
  11.         }
  12.         
  13.         public static double aa() throws Exception{
  14.             double b = 0;
  15.             try{
  16.                 b=1/0;
  17.             }catch(ArithmeticException e){
  18.                 throw new ArithmeticException(e.getMessage());
  19.             }
  20.             return b;
  21.         }
  22.     
  23.     }


输出:
java.lang.ArithmeticException: / by zero
    at test.s.yichang.aa(yichang.java:18)
    at test.s.yichang.main(yichang.java:6)

说明:因为知道aa方法抛出的异常是ArithmeticException,所以准确定位第一层异常捕获。然后在main方法中也精确捕获到aa方法抛来的算术异常。


总结:

       正确使用try catch 异常,try 不是能吃掉所有的异常,必须要在catch中使用正确的异常才能捕获。但是在实际开发中,很难精确的捕获可能存在的异常。因此我们大多使用第一种情况,exception是所有异常的父类,能捕获到所有的异常。

      新增:对于方法套嵌层级很多的,如果在最外层的方法被try catch,那么无论多少层级,最后都会被最外层的try catch捕获到,比如说在实际工作中我们经常会看到这样的代码,最外层的方法被try catch,如果有个方法出现空指针异常,那么最后打印的信息会是最外层catch输出的错误说明。

                                            

扫码关注本人微信公众号,有惊喜奥!公众号每天定时发送精致文章!回复关键词可获得海量各类编程开发学习资料!

例如:想获得Python入门至精通学习资料,请回复关键词Python即可。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/277060
推荐阅读
相关标签
  

闽ICP备14008679号