`

【总结】杂谈Java异常处理

阅读更多

软件开发中一个古老的说法是:80%的工作使用20%的时间。80%是指检查和处理错误所付出的努力。在许多语言中,编写检查和处理错误的程序代码很乏味,并使应用程序代码变得冗长。原因之一就是它们的错误处理方式不是语言的一部分。尽管如此,错误检测和处理仍然是任何健壮应用程序最重要的组成部分。

 

Java 提供了一种很好的机制,用强制规定的形式来消除错误处理过程中随心所欲的因素:异常处理。它的优秀之处在于不用编写特殊代码检测返回值就能很容易地检测错误。而且它让我们把异常处理代码明确地与异常产生代码分开,代码变得更有条理。异常处理也是Java中唯一正式的错误报告机制。

 

      1、抛出异常。所有的标准异常类都有两个构造器:一个是缺省构造器,一个是带参数的构造器,以便把相关信息放入异常对象中。
                    throw new NullPointerException();
                    throw new NullPointerException("t = null");

 

      2、如果有一个或者多个catch块,则它们必须紧跟在try块之后,而且这些catch块必须互相紧跟着,不能有其他任何代码。C++没有这样的限制,所以 C++的异常处理处理不好就会写得很乱,抛来拋去的。

 

      3、使用try块把可能出现异常的代码包含在其中,这么做的好处是:处理某种指定的异常的代码,只需编写一次。作业没写完的同学到走廊罚站去,这符合我们处理问题的方式,不用挨个地告诉。

 

      4、无论是否抛出异常,finally块封装的代码总能够在try块之后的某点执行。

try {    
     return ;    
}    
finally {    
      System.out.print("You can't jump out of my hand!");    
}  

      甚至你在try块内用return语句想跳过去都不可以!finally内的输出语句还是执行了!别想逃出我的手掌心!

 

      5、catch块和finally块是可选的,你可以只使用try。但是这么做有意思吗?

 

      6、推卸责任。Java允许你推卸责任,没有必要从相应的try块为每个可能的异常都编写catch子句。Java2类库中很多方法都会抛出异常,就是是把异常处理的权限交给了我们用户。毕竟,Java不知道你的自行车被偷了之后,你会去报案还是会忍气吞声自认倒霉,或者偷别人的自行车。我们需要这种处理异常的自由度。

 

       7、调用栈。调用栈是程序执行以访问当前方法的方法链。被调用的最后一个方法在栈的顶部,它将被最先执行完毕,然后弹出;第一个调用方法位于底部,也就是 main函数。在catch子句中使用printStackTrace()方法打调用栈信息是比较常用的定位异常的方法。 printStackTrace()继承自Throwable。

 

       8、异常的传播。在一个方法A中,如果一个异常没有得到处理,它就会被自动抛到调用A方法的B方法中。如果B方法也没有处理这个异常,他就会被继续依次向上抛,直到main 方法。如果main也没有理会它,那么异常将导致JVM停止,程序就中止了。你被同学揍了,先去告诉老师。老师不理你你就去告诉教导处主任,教导处主任也不管那只能告诉校长,校长还不管!没有比他更大的了,于是你崩溃了,学业中止了……下面这段程序记录了悲惨的辍学历史:

class ExceptionDemo{    
         static void student() throws Exception { teacher(); }    
         static void teacher() throws Exception { schoolmaster(); }    
         static void schoolmaster() throws Exception { throw new Exception(); }    
          public static void main(String[] args) {    
                   try{    
                         student();    
                   } catch (Exception e) {    
                         e.printStackTrace();    
                   }    
          }    
}  
 /*输出结果是: java.lang.Exception     
    at ExceptionDemo.schoolmaster(ExceptionDemo.java:9)    
    at ExceptionDemo.teacher(ExceptionDemo.java:6)    
    at ExceptionDemo.student(ExceptionDemo.java:3)    
    at ExceptionDemo.main(ExceptionDemo.java:13)
*/

      可以看出函数的调用栈,一级一级地哭诉……

 

      9、异常的层次结构及Error。Throwable 继承自Object,Error和Exception继承自Throwable。Error比较特殊,它对应于我们常说的不可抗拒的外力,房屋中介的合同上总有一条,如遇不可抗拒的外力本合同中止,返还乙方押金。我不安地问:不可抗拒的外力指什么?中介回答:比如战争、彗星撞击地球等。对Java来说 Error是指JVM内存耗尽等这类不是程序错误或者其他事情引起的特殊情况。一般地,程序不能从Error中恢复,因此你可以能眼睁睁地看着程序崩溃而不必责怪自己。严格来讲,Error不是异常,因为它不是继承自Exception。

 

      10、谁之错? 一般地,异常不是我们程序员的错,不是程序设计上的缺陷。比如读取一个重要文件,这个文件被用户误删了;正上着网呢,网线被用户的宠物咬断了。为了程序的健壮性,我们尽量考虑出现可能性大的异常,并处理,但我们不能穷尽。

 

      11、异常的捕获之一。catch子句的参数是某种类型异常的对象,如果抛出的异常是该参数的子类,那么这个异常将被它捕获。也就是说被抛出的异常不会精确地寻找最匹配的捕获者(catch子句),只要是它的继承结构的直系上层就可以捕获它。 按照这个逻辑,catch(Exception e) 不就能捕获所有的异常吗?事实上,确实如此。但是一般地,不建议使用这种一站式的异常处理。因为这样就丢失了具体的异常信息,不能为某个具体的异常编写相应的异常处理代码,失去了异常处理的意义。从哲学角度来讲,具体问题要具体分析,能治百病的万能药一般都是无效的保健品。 Java在此处为什么这么设计呢?因为有另一种机制的存在,请看下条分解。

 

      12、异常的捕获之二。当抛出一个异常时,Java试图寻找一个能捕获它的catch子句,如果没找到就会沿着栈向下传播。这个过程就是异常匹配。Java规定:最具体的异常处理程序必须总是放在更普通异常处理程序的前面。这条规定再合理不过了,试想如果把catch(Exception e)放在最上面,那么下面的catch子句岂不是永远不能执行了?如果你非要把更普遍的异常处理放在前面,对不起,通不过编译!虽然编译器不会这样报错:“It is so stupid to do like that!”……

 

      13、异常捕获之三。如果某个异常发生的时候没有在任何地方捕获它,或者捕获到的异常并不是在catch子句中声明的异常类型,那么程序会终止执行,并在控制台上显示异常信息,包括异常的类型和堆栈内容。
      当然,如果我们是有try捕获异常后,在catch中匹配到了这种要处理的异常,程序将继续执行下去。


      14、捕获或声明规则。如果在一个方法中抛出异常,你有两个选择:要么用catch子句捕获所有的异常,要么在方法中声明将要抛出的异常,否则编译器不会让你得逞的。

//方案一:处理异常    
void ex() {   
       try {    
                throw new Exception();    
       }catch(Exception e) {    
                e.printStackTrace();    
       }    
}   
 //方案二:抛出去    
void ex() throws Exception {   
       throw new Exception();    
}  

      比较一下行数就知道了,在代码的世界里推卸责任也是那么简单,一个throws关键字包含了多少人生哲理啊……现实生活中我们有很多角色,儿女、父母、学生、老师、老板、员工……每个人都占了几条。可是你能尽到所有责任吗?按照古代的孝道,父母尚在人世就不能远行。各种责任是有矛盾的,顾此失彼啊。但是这条规则有个特例。一个继承自Exception名为RuntimeException的子类,也就是运行时异常,不受上述规则的限制。下面的代码完全能编译,只不过调用之后在运行时会抛出异常。

void ex() {    
       throw new RuntimeException();    
}  

 

      15、throw和thrwos关键字。throw 用在方法体中抛出异常,后面是一个具体的异常对象。throws用在方法参数列表括号的后面,用来声明此方法会抛出的异常种类,后面跟着一个异常类。

 

      16、非检查异常。RuntimeException、Error以及它们的子类都是非检查异常,不要求定义或处理非检查异常。Java2类库中有很多方法抛出检查异常,因此会常常编写异常处理程序来处理不是你编写的方法产生的异常。这种机制强制开发人员处理错误,使得Java程序更加健壮, 安全 。

 

      17、自定义异常类型。觉得现有的异常无法描述你想抛出的异常,ok!Java允许你自定义异常类型,只需要继承Exception或者它的子类,然后换上有个性的名字。

class NotEnoughMoney extends Exception {   
             public NotEnoughMoney() { }   
             public NotEnoughMoney(String msg) { super(msg); }   
}  

      希望大家在生活里不要抛出类似的异常。

 

      18、重新抛出异常。一个很无聊的话题,纯粹的语法研究,实际意义不大。当catch子句捕获到异常之后可以重新抛出,那么它所在的方法必须声明该异常。

 

       19、终止与恢复模型。异常处理理论上有两种模型:
        终止模型。错误很关键且无法挽回,再执行下去也没意义,只能中止。“罗密欧,我们分手吧!”“好吧,朱丽叶!”

double number;    
String sNumber = "";    
try {    
         BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));    
         sNumber = bf.readLine();    
         number = Double.parseDouble(sNumber);    
} catch (IOException ioe) {    
         System.err.println("some IOException");    
} catch (NumberFormatException nfe) {    
         System.err.println(sNumber + " is Not a legal number!");    
}    
//System.out.println(number);  

         恢复模型。经过错误修正重新尝试调用原来出问题的方法。“罗密欧,我们分手吧!”“朱丽叶,我错了!请再原谅我一次吧!”“好的,再原谅你最后一 次!” 显然我们更喜欢恢复模型,但在实际中,这种模式是不易实现和维护的。例子:用户输入了非法的字符,分别按照两种模式处理一、终止模型。输出出错信息而已, 一旦用户手一抖眼一花你的代码就崩溃了。恢复模型。小样!不输入正确的数据类型就别想离开!

double number = 0;    
String sNumber = "";    
while(true) {    
      try{    
             BufferedReader bf = new BufferedReader(new InputStreamReader (System.in));    
             sNumber = bf.readLine();    
             number = Double.parseDouble(sNumber);    
             break; //如果代码能执行到这一行,就说明没有抛出异常    
    }catch (IOException ioe) {    
             System.err.println("some IOException");    
      }catch (NumberFormatException nfe) {    
             System.err.println(sNumber + " is Not a legal number!");    
      }    
}    
System.out.println(number);  

 

      20、try、catch、finally内变量的作用域和可见性。 在 try块内定义的变量,它在catch或者finally块内都是无法访问到的,并且在整个异常处理语句之外也是不可见的。补充一点初始化:第一个例中最后一句被注释掉了。number是在运行时由用户输入而初始化的,但是在编译时刻并没有初始化,编译器会抱怨的。

 

      21、输出异常信息。捕捉到异常之后,通常我们会输出相关的信息,以便更加明确异常。

catch (Exception mex) {   
        System.err.println("caught a exception!");   
}  
 
分享到:
评论
3 楼 jiasanshou 2011-11-05  
  
2 楼 polaris37 2011-09-02  
写的不错哦,拜读
1 楼 polaris37 2011-09-02  
                                  :ar[/size][size=xx-large][/url][url][/url][url][/url][url][/url][url][flash=200,200][/flash]
row:

相关推荐

    JAVA杂谈

    ### JAVA杂谈:深入探索Java的核心机制与实践 #### 动态加载机制解析 Java的动态加载机制是其面向对象编程(OOP)理念的核心体现之一,它使得Java能够在运行时根据需要加载类,而非在程序启动之初加载所有类。这种...

    java杂谈

    ### Java杂谈:深入理解Java的关键概念 #### 动态加载机制:理解OOP思想的桥梁 Java作为一种纯粹的面向对象编程语言,其设计之初便致力于简化和优化面向对象编程(OOP)的概念,使之更加直观易懂。动态加载机制便是...

    java学习杂谈

    ### Java学习杂谈:深入解析Java的动态加载机制、类搜索原理及JDK与JRE的区别 #### 动态加载机制解析 Java的学习者往往在掌握面向对象编程(OOP)概念时,会遇到“动态加载机制”这一关键点。相较于C++中面向过程...

    Java学习杂谈1-12

    Java学习杂谈系列涵盖了许多关于Java编程的基础概念和机制,以下是对这些知识点的详细解读: 1. **动态加载机制**: 动态加载机制是Java语言的一个关键特性,它使得程序在运行时才能确定哪些类需要加载。当你声明...

    java陷阱--面试(题集)杂谈

    键字)用于声明变量、方法或类,表示不可变或最终...以上是Java面试中常见的问题及答案,涵盖了Java的基础语法、面向对象、集合、多线程、异常处理等多个方面。掌握这些知识点对于成为一名合格的Java开发者至关重要。

    计算机杂谈总结免费下载

    计算机杂谈总结免费下载

    杂谈try-catch-finally异常处理

    相关阅读:再谈异常处理try catch finally 1. 前言 最近这段时间正开发一个店铺管理系统,这个项目定位于给中小型店铺使用的软件系统。简单的说,它处理商品的进货,销售,退货等功能。软件虽小,五脏俱全,里面...

    java杂谈——一个计算机专业学生几年的编程经验汇总谈

    ### Java杂谈——一个计算机专业学生几年的编程经验汇总谈 #### 一、关于动态加载机制 在Java中,动态加载机制是实现高效资源管理的关键之一。它允许Java虚拟机(JVM)根据需要加载类,而不是一次性加载所有的类。...

    Java面试题解惑系列

    来自网络,主要包括以下内容:1、类初始化的顺序;...6.String杂谈;7.日期与时间的处理;8.基本类型总结;9.继承,多态,重载,重写;10.多线程;11.运算符总结。 适合将要笔试面试Java的朋友参考。

    java陈国君(第二版)课件

    函数式编程理念可以帮助编写更简洁、可读性强的代码,异常处理则是保障程序健壮性的重要手段,而垃圾回收和内存管理则关系到Java程序的性能和稳定性。 此外,课件可能还会涵盖Java的网络编程、多线程编程、I/O操作...

    JAVA面试题解惑系列合集

    - finally是try-catch结构中用来处理异常的最后环节,无论是否捕获到异常,finally块中的代码都会被执行。 - finalize是Object类中的一个方法,当对象不再被引用时,垃圾回收器会调用finalize方法来清理资源。 5. ...

    再谈异常处理try catch finally

    在上篇文章杂谈异常处理try-catch-finally中主要详细介绍了C#异常处理的概念,异常设计准则,基础知识等方面的内容,但对如何正确使用异常处理印象还不是特别深刻吧。在这篇中,我通过查找以前系统代码中存在坏味道...

    程序设计经验杂谈,程序设计,经验杂谈

    例如,Python有PEP 8,Java有Google Java Style Guide,这些都是值得遵循的编码规范。 最后,项目管理在大型项目中扮演着重要角色。了解敏捷开发理念,如Scrum或Kanban,可以帮助团队有效地组织和管理任务。同时,...

    java杂谈-一个计算机专业学生几年的编程经验汇总谈.pdf

    Extension ClassLoader处理`jre/lib/ext`路径下的扩展类库;而Application ClassLoader则加载当前路径或classpath指定的位置的类。你可以通过调用`new A().getClass().getClassLoader().toString()`来查看类A是由...

    java杂谈-一个计算机专业学生几年的编程经验汇总谈实用.pdf

    总结来说,这篇文章提供了对Java编程基础的深入理解,特别是动态加载机制、类查找过程以及JDK和JRE的差异。这些知识对于Java开发者来说至关重要,可以帮助他们更好地调试和优化代码,提高开发效率。通过实践和探索...

    高并发场景杂谈.zip

    总结来说,这些文档涵盖了从数据库优化、分布式系统设计到网络架构调整等多个层面,为处理高并发问题提供了全面的视角和实践经验。无论是百万级还是千万级的并发,都可以从中找到适应不同场景的解决方案。理解并掌握...

Global site tag (gtag.js) - Google Analytics