zoukankan      html  css  js  c++  java
  • Java通用异常处理错误

    ​ 发现错误最理想的时机在编译阶段,然而编译期间并不能找出所有的错误,余下的问题必须在运行期间解决。这就需要错误源能通过某种方式,把适当的信息传递给某个接收者——该接收者知道将知道如何正确处理这个问题。

    1.1 概念

    ​ 使用异常所带来的好处是,它往往能降低错误处理代码的复杂度。如果不使用异常,那么就必须检查特定的错误,并在程序中的许多地方去处理它。而如果使用异常,那就不必在方法调用处进行检查,因为异常处理机制能保证捕获到这个错误。并且,只需在一个地方处理错误,即所谓的异常处理程序中。这种方式不仅节省代码,而且把“描述在正常执行过程中做什么事”的代码和“出了问题怎么办”的代码相分离。

    1.2 基本异常

    ​ 异常情形(exceptional condition)是指阻止当前方法或作用域继续执行的问题。把异常情形与普通问题区分很重要,所谓普通问题是指,在当前环境下能得到足够的信息,总能处理这个错误。而对于异常情形,就不能继续下去了,因为在当前环境下无法获得必要的信息来解决这个问题。

    ​ 对于异常情形,你所能做的就是从当前环境跳出,并且把问题提交给上一级环境。这就是抛出异常时所发生的事情。

    ​ 当抛出异常后,有几件事情会随之发生。首先,同Java中其它对象的创建一样,将使用new在堆上创建异常对象。然后当前的执行路径被终止了,并且从当前环境中弹出对异常对象的引用。此时,异常处理机制接管程序,并开始寻找一个恰当的地方来继续执行程序。这个恰当的地方就是异常处理程序,它的任务是将程序从错误状态中恢复,以使程序要么换一种方式运行,要么继续运行下去。

    1.3 捕获异常

    ​ 要明白异常是如何被捕获的,必须首先理解监控区域(guarded region)的概念。它是一段可能产生异常的代码,并且后面跟着处理这些异常的代码。try{}包含的语句块就是监控区域,后面跟着catch{}就是处理这些异常的代码。

    终止与恢复

    ​ 异常处理理论上有两种基本模型。Java支持终止模型,在这种终止模型中,将假设错误非常关键,以至于程序无法返回到异常发生的地方继续执行。一旦异常被抛出,表明错误已无法挽回,不能回来继续执行。

    ​ 另一种称为恢复模型。意思是异常处理程序的工作是修正工作,然后尝试重新调用出问题的方法,并认为第二次能成功。对于恢复模型,通常希望异常处理之后能继续执行程序。如果希望Java能实现类似恢复的行为,那么在遇见错误时就不能抛出异常,而是调用方法来修正该错误。或者,把try块放在while循环里,这样就不断进入try块,知道得到满意的结果。

    ​ 长久以来,尽管使用的操作系统支持恢复模型,但是我们最终还是转向使用类似“终止模型”的代码,并且忽略恢复行为。其中的原因是恢复模型导致的耦合:恢复性的处理程序需要了解异常抛出的位置,这势必要包含依赖于抛出位置的非通用性代码。这增加了代码编写和维护的难度,对于异常可能会从许多地方抛出的大型程序来说,更是如此。

    1.4 创建自定义异常

    ​ 要自己定义异常类,要从已有的异常类继承,最好选择意思相近的异常类继承。

    class SimpleException extends Exception{}
    
    public class A{
    	public void f() throws SimpleException{
    		throw new SimpleException();
    	}
    	
    	public static void main(Stirng[] args){
    		A a = news A{};
    		try{
    			a.f();
    		}catch(SimpleException e){
    			System.out.println("Caught it!");
    		}
    	}
    }/* Output:
    Caught it!
    *///:~
    

    ​ 编译器创建了默认构造器,它将自动调用基类的默认构造器。本例不会得到像SimpleException(String)这样的构造器,这种构造器也不实用,对异常来说,最重要的部分就是类名。当然也可以为异常类定义一个接受字符串参数的构造器。

    1.5 Java标准异常

    ​ Throwable这个类被用来表示任何可以作为异常被抛出的类。Throwable对象可分为两种类型(指从Throwable继承而得到的类型):Error用来表示编译时和系统错误;Exception是可以被抛出的基本类型,在Java类库、用户方法以及运行时故障中都可能抛出Exception型异常。

    ​ 异常的基本概念是用名称代表发生的问题,并且异常的名称应该可以望文知意。

    特例:RuntimeException

    ​ 像NullPointerException这种属于运行时异常的类型,它们会自动被Java虚拟机抛出,所以不必在异常说明中把它们列出来。这体现了继承的优点,它们也被称为“不受检异常”。这种异常属于错误,它会被自动捕获。

    1.6 使用finally进行清理

    ​ 对于一些代码,可能会希望无论try中的异常有没有抛出,它们都能得到执行。这通常适用于内存回收之外的情况(因为回收由垃圾回收器完成)。为了达到这个效果,可以在异常处理程序后面加上finally子句。

    ​ 对于没有垃圾回收和析构函数自动调用机制的语言来说,finally非常重要,它能使程序员保证:无论try块里发生什么,内存总能得到释放。但Java有垃圾回收机制,所以内存释放不再是问题。而且Java也没有析构函数可供使用。那么,Java在什么情况下才会用到finally呢?

    ​ 当要把除内存之外的资源恢复到它们的初始状态时,就要用到finally子句。这种需要清理的资源包括:已经打开的文件或网络连接,在屏幕上画的图形,甚至可以是外部世界的某个开关。

    缺憾:异常丢失

    ​ Java的异常实现也有瑕疵,异常作为程序出错的标志,决不应该被忽略,但它还是有可能被轻易地忽略。

    一种简单的丢失异常的方式是从finally子句中返回:

    public class ExceptionSilencer{
    	public static void main(String[] args){
    		try{
    			throw new RuntimeException();
    		}finally{
    			return;
    		}
    	}
    }
    

    ​ 如果运行这个程序,就会看到即使异常抛出了,也不会产生任何输出。

    1.7 构造器中的异常处理

    ​ 有一点很重要,即你要时刻询问自己“如果异常发生了,所有东西能被正确的清理吗?”。尽管大多数情况下是安全的,但是涉及到构造器时,问题就出现了。

    ​ 构造器会把对象设置成安全的初始状态,但还会有别的动作,比如打开一个文件,这样的动作只有在对象使用完毕并且用户调用了特殊的清理方法之后才能清理。如果在构造器内抛出了异常,这些清理行为也许就不能正常工作了。这意味着在编写构造器时要格外小心。

    ​ 也许你会以为使用finally就可以解决问题。但问题并非如此简单,因为finally会每次都执行清理代码。如果构造器在其执行过程中半途而废,也许该对象的某些部分还没有被成功创建,而这些部分在finally子句中却是要被清理的。

    (具体例子请详细阅读Java编程思想P272)

  • 相关阅读:
    电脑开机自动上线(电脑开机之后自动将电脑的远程端口映射到服务器,可以通过其他设备进行连接,实现随时访问自己的电脑)
    批处理(bat)用来监测Windows网络状态脚本
    js取消点击事件
    uni-app 几个实用的功能
    前端几个比较方便的正则验证
    element.ui时间选择器
    Vue pc端项目打包后在nginx中无法正常浏览,点击页面出现404
    微信小程序之选项卡的实现方法
    文本溢出显示省略号
    分享几道前端面试题(3)
  • 原文地址:https://www.cnblogs.com/wutongblog/p/11187860.html
Copyright © 2011-2022 走看看