您的位置 首页 java

解读Java编程思想–异常处理

写软件时,我们总是想着怎样能够减少软件的复杂性?而且不像是一种命令式编程,徒增软件复杂性,最终导致开发人员累个半死,解决的bug存在治标不治本的问题。还有一些问题,比如不想查看自己写的代码。类似这样的问题。

1.通过异常处理错误

Java的基本理念是“结构不佳的代码不能运行”。

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

Java使用异常来提供一致的错误报告模型。

与使用Java中的其他对象一样,我们总是用new在堆上创建异常对象。所有标准异常类都有两个 构造器 :一个是默认构造器,另一个是接受字符串作为参数,以便能把相关信息放入异常对象的构造器。

1.1.捕获异常

如果在方法内部抛出了异常,这个方法将在抛出异常的过程中结束。但如果不希望方法就此结束,可以在方法内设置一个特殊的块来捕获异常。

而异常处理程序紧跟在try块之后,以关键字catch表示。当异常被抛出时,异常处理机制将负责搜寻参数与异常类型相匹配的第一个处理程序,然后进入catch子句执行。

 try{
    // 可能会产生异常的代码块
}catch(Type1 id1){
    // 处理Type1的异常
}catch(Type2 id2){

}catch(Type3 id){

}123456789复制代码类型:[java]  

1.2.创建自定义异常

要自己定义异常类,必须从已有的异常类继承。

 class SimpleException extends Exception{}

public class InheritingExceptions{
    public void f()throws SimpleException{
        System.out.println("Throw SimpleException from f()");
        throw new SImpleException();
    }

    public static void main(String[] args){
        InheritingException sed = new InheritingException();

        try{
            sed.f();
        }catch(SimpleException e){
            System.out.println("Caught it);
        }
    }
}123456789101112131415161718复制代码类型:[java]  

1.3.异常说明

异常说明属于方法声明的一部分,紧跟在形式参数列表之后,使用了关键字throws,后面接着一个所有潜在异常类型的列表。

 void f() throws TooBig, TooSmall{
    //...
}123复制代码类型:[java]  

1.4.捕获所有异常

可以只写一个异常处理程序来捕获所有类型的异常:

 catch(Exception e){
    System.out.println("Caught an exception");
}123复制代码类型:[java]  

最好把它放在处理程序列表的末尾,以防它抢在其他处理程序之前先把异常捕获了。

可以使用 Exception 从基类Throwable继承的方法来获取异常信息,如getStackTrace()方法将返回一个由栈轨迹中的元素所构成的数组,其中每个元素都表示栈中的一帧。元素0是栈顶元素,并且是调用序列中的最后一个方法调用,也就是这个Throwable被创建和抛出之处。

可以在得到了对当前异常对象的引用时,把它重新抛出。重抛异常会把异常抛给上一级环境中的异常处理程序,异常对象的所有信息都得以保持,所以高一级环境中捕获此异常的处理程序可以从这个异常对象中得到所有信息。

如果只是把当前异常对象重新抛出,printStackTrace()方法显示的是原来异常抛出点的调用栈信息,而非重新抛出点的信息。想要更新这个信息,可以调用fillInStackTrace()方法,这将返回一个Throwable对象,它是通过把当前调用栈信息填入原来那个异常对象而建立的。

如果想要捕获一个异常后抛出另一个异常,并且希望把原始异常的信息保存下来,这被称为异常链。Throwable的子类的构造器中可以接受一个cause对象作为参数,用这个cause来表示原始异常。通过把原始异常传递给新的异常,可以通过这个异常链追踪到异常最初发生的位置。

1.5.Java标准异常

Throwable这个Java类被用来表示任何可以作为异常被抛出的类。Throwable对象可分为两种类型:

•Error用来表示编译时和系统错误

•Exception是可以被抛出的基本类型

RuntimeException则属于特例。运行时异常的类型有很多,它们都是从RuntimeException类继承而来并且会自动被Java虚拟机抛出,所以不必在异常说明中把它们列出来,它们也被称为“不受检查异常”。

只能在代码中忽略RuntimeException及其子类类型的异常,其他类型异常的处理都是由编译器强制实施的。

1.6.使用finally进行清理

如果希望无论try块中的异常是否抛出,都能执行一些代码,这通常适用于内存回收之外的情况,可以在异常处理程序后面加上finally子句。

下面的例子可以证明finally子句总能运行:

 class ThreeException extends Exception {
}

public class FinallyWorks {
    static int count = 0;

    public static void main(String[] args) {
        while (true) {
            try {
                if (count++ == 0) {
                    throw new ThreeException();
                }
                System.out.println("No exception");
            }catch (ThreeException e){
                System.out.println("ThreeException");
            }finally {
                System.out.println("In finally clause");
                if(count == 2)
                    break;
            }
        }
    }
}1234567891011121314151617181920212223复制代码类型:[java]  

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

甚至在异常没有被当前的异常处理程序捕获的情况下,异常处理机制也会在跳到更高一层的异常处理程序之前,执行finally子句。因为finally子句总是会执行,所以可以在一个方法中从多个点返回,并且可以保证重要的清理工作仍旧会执行。

要注意的是,在finally子句中直接返回是会丢失异常的。

1.7.异常的限制

当覆盖方法的时候,只能抛出在基类方法的异常说明里列出的那些异常,这样当基类使用的代码应用到其派生类对象的时候,一样能够工作,异常也不例外。

尽管在继承过程中,编译器会对异常说明做强制要求,但异常说明本身并不属于方法类型的一部分,所以不能基于异常说明来重载方法。此外一个出现在基类方法的异常说明中的异常,不一定会出现在派生类方法的异常说明里,而在继承中,基类的方法必须出现在派生类里。

1.8.构造器

如果在构造器内抛出了异常,清理行为也许就不能正常工作了。

对于在构造阶段可能抛出异常,并且要求清理的类,最安全的使用方式是使用嵌套的try子句。这种通用的清理惯用法在构造器不抛出任何异常时也应该运用,其基本规则是:在创建需要清理的对象之后,立即进入一个try-finally语句块。

1.9.异常匹配

抛出异常的时候,异常处理系统会按照代码的书写顺序找出最近的处理程序。但是查找的时候不要求抛出的异常同处理程序所声明的异常完全匹配,派生类的对象也可以匹配其基类的处理程序。

1.10.其他可选方式

对于简单的程序,可以把异常信息从main()传递到控制台,也就是main()方法上加入异常说明。

对于普通方法,可以直接把被检查的异常包装进RuntimeException里,如:

 try{
    //...
}catch(IDontKnowWhatToDoWithThisCheckedException e){
    throw new RuntimeException(e);
}12345复制代码类型:[java]  

这样不用“吞下”异常,也不用把它放到方法的异常说明里,而异常链还能保证不会丢失任何原始异常的信息。

1.11.异常使用指南

应该在下列情况中使用异常:

•在恰当的级别处理问题,也就是在知道如何处理的情况下才捕获异常

•解决问题并且重新调用产生异常的方法

•进行少许修补,然后绕过异常发生的地方继续执行

•用别的数据进行计算,以代替方法预计会返回的值

•把当前运行环境下能做的事情尽量做完,然后把异常抛到更高层

•终止程序

•进行简化

•让类库和程序更安全

文章来源:智云一二三科技

文章标题:解读Java编程思想–异常处理

文章地址:https://www.zhihuclub.com/191368.shtml

关于作者: 智云科技

热门文章

网站地图