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

    一、概念

    • 异常机制使代码的阅读、编写和调试工作更加井井有条。
    • Java异常处理的目的在于通过使用少于目前数量的代码来简化大型、可靠的程序的生成,并且通过这种方式可以使你更自信:你的应用中没有未处理的错误。

    二、基本异常

    异常情形:
    • 是指组织当前方法或作用域继续执行的问题。
    抛出异常:
    • 异常情形发生时,程序在当前环境无法获得必要的信息来解决问题,不能继续执行,这是只能从当前环境跳出,把问题提交给上一级环境。
    • 抛出异常流程:
      1、在堆上new一个异常对象
      2、当前执行路径种植,并且从当前环境中弹出对异常对象的引用
      3、异常处理机制接管程序,并开始寻找一个恰当的地方(异常处理程序)来执行程序。
    • 异常的作用:
      1、异常是我们可以将每件事都当作一个事务来考虑,而异常可以看护着这些事务的底线
      2、异常可以看作是一种内建的恢复系统,当程序的某部分失败了,异常将“恢复”到程序中某个已知的稳定点。
      3、异常最重要的方面就是如果发生问题,不允许程序沿着其正常的路径继续走下去。
    异常参数
    • 所有标准异常类都有两个构造器:一个是默认构造器;另一个是接受字符串(错误信息)作为参数。

    三、捕获异常

    监控区域:
    • 一段可能产生异常的代码,并且后面跟着处理这些异常的代码。
    try块:
    • 把所有可能产生异常的动作放到try块中,然后在一个地方就可以捕获所有异常。
    异常处理程序
    • 抛出的异常必须在某处得到处理,这个地点就是异常处理程序,以紧跟在try块之后的catch块表示。
      catch块可以有多个,当异常被抛出时,异常处理程序只会处理第一个匹配的抛出异常,然后不会再执行剩下的语句。
    终止与恢复

    异常处理理论上有两种基本模型:

    • Java支持终止模型,这这种模型中,假设错误非常关键,以至于程序无法返回到异常发生的地方继续执行。一旦异常被抛出,就表明错误已无法挽回,也不能回来继续执行。
    • 另一种成为恢复模型,意思是异常处理程序的工作是执行错误,然后重新尝试调用出问题的方法,并认为第二次可以成功。回复模型不实用的主要原因是它所导致的耦合:恢复性的处理程序需要了解异常抛出的地点,这势必要包含依赖于抛出位置的非通用性代码。

    四、创建自定义异常

    Java提供的异常体系不可能预见所有的希望加以报告的错误,所以可以自己定义异常类。创建自定义异常类,必须从已有的异常类继承,最好是选择意思相近的异常类继承。

    System.err与System.out
    • 通过System.err可以将错误发送给标准错误流,这通常比把信息输出到System.out要好,因为System.out也许会被重定向,而System.err不会。e.printStackTrace()也是把信息发送给System.err。
    异常与记录日志:
    class LoggingException extends Exception {
        private static final Logger LOGGER = Logger.getLogger("LoggingException");
    
        public LoggingException() {
    //        StringWriter writer = new StringWriter();
    //        printStackTrace(new PrintWriter(writer));
            LOGGER.severe(this.toString());
        }
    }
    

    如上所示:可以把异常的信息打印到日志java.util.logging中,默认的日志输出是System.err,也可以配置为文件等。

    public class Test {
        private static final Logger LOGGER = Logger.getLogger("Test");
    
        static void logException(Exception e) {
    //        StringWriter writer = new StringWriter();
    //        printStackTrace(new PrintWriter(writer));
            LOGGER.severe(e.toString());
        }
    
        public static void main(String[] args) {
            try {
                throw new RuntimeException();
            } catch (Exception e) {
                logException(e);
            }
        }
    }
    

    如上所示:一般来说,在自定义的异常类(以及其他人的异常类)中不会耦合日志系统的信息,我们需要捕获异常然后输出异常信息到日志系统,所以需要在异常处理程序中产生日志消息。

    • 一般来说,异常最重要的信息就是抛出的异常类本身,其他的功能基本上不用去管。

    五、捕获所有异常

    因为Exception是所有异常的基类,所以通过catch(Exception e)可以捕获所有异常。
    尽量捕获子类的异常,这样可以携带更加细节的信息,最好把catch(Exception e)放在处理程序的末尾,防止它在其他处理程序之前先把异常捕获了。

    栈轨迹
    • printStackTrace()方法所提供的信息可以通过getStackTrace()方法来直接访问,这个方法返回由栈轨迹中的所有元素构成的数组,其中每一个元素都表示栈中的一帧。
    • 数组中第0个元素是栈顶元素,并且是调用序列中的最后一个方法调用,并且数组中元素下标按照调用过程逆序排列。
    • 数组中每个元素StackTraceElement,由类名、方法名、文件名、第几行组成。
    重新抛出异常
    • 可以把捕获的异常在catch块中向上一级环境中抛出,此时同一个try块中其他catch块将会被忽略。
    • 调用e.fillInStackTrace()可以返回一个Throwable对象,它是通过把当前的调用栈信息填入原来的异常对象,此时该行将成为异常新的发生地,之前的异常在printStackTrace()方法中将不会打印(但没有丢失)。
    • 捕获原来的异常之后可以抛出另一个新的异常,效果类似与e.fillInStackTrace(),不同的是有关原来异常发生点的信息会被丢失,只剩下新的异常抛出点。
    异常链
    • 捕获原来的异常之后可以抛出另一个新的异常,并且希望把原始异常的信息保存下来,这就是异常链。
    • Throwable的子类在构造器中接受一个cause对象作为参数,这个cause就表示原始异常,此时就可以在抛出新异常的同时追踪到之前的异常。
    • 要注意的是,Throwable的子类并不一定有这个构造器,此时你可以用initCause()方法。
    • 通过e.getCause()获取原始异常。
    public class Test {
        public static void main(String[] args) throws Exception {
            try {
                g();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        private static void f() throws Exception {
            throw new IndexOutOfBoundsException();
        }
    
        private static void g() throws Exception {
            try {
                f();
            } catch (Exception e) {
                // throw new RuntimeException(e);
                RuntimeException ee = new RuntimeException();
                ee.initCause(e);
                throw ee;
            }
        }
    }
    // Output:
    java.lang.RuntimeException: java.lang.IndexOutOfBoundsException
        at s2.Test.g(Test.java:26)
        at s2.Test.main(Test.java:11)
    Caused by: java.lang.IndexOutOfBoundsException
        at s2.Test.f(Test.java:18)
        at s2.Test.g(Test.java:23)
        ... 1 more
    

    六、Java标准异常

    Throwable这个类被用来表示任何可以作为异常抛出的类。它分为两种类型:
    • Error:表示编译时和系统错误,除特殊情况外,我们不需要理会此异常。
    • Exception:可以被抛出的异常,在JAVA类库、用户方法及运行时故障中都可能抛出的异常,我们通常关心此异常。
    RuntimeException

    运行时异常(也称为不受检查异常)会被JVM自动抛出,所以不需要异常说明中把它们列出来。

    • 只能在代码中忽略RuntimeException及其子类型的异常,其它类型的异常的处理都是由编译器强制执行的,RuntimeException代表的是编程错误:
      1、无法预料的错误,比如从控制范围外传递来的null引用。
      2、程序员应该在代码中检查及避免的错误。
      3、在一个地方发生的异常,常常会在另一个地方发生错误。
    • 不应该把异常处理机制当做是单一的用途的工具
      虽然它被设计用来处理一些烦人的运行时错误,这些错误往往是由代码控制范围外的不确定因素导致的,但是它对于发现某些编译器无法检测到的编程错误也是很有帮助的。

    七、异常使用指南

    异常处理的一个重要原则:只有在你知道如何处理的情况下才捕获异常。
    异常处理的一个重要目标:就是把错误处理的代码同错误发生的地点相分离。
    • 在恰当的级別处理问题。(在知道该如何处理的情况下才捕获异常)
    • 解决问题并且重新调用产生异常的方法。
    • 进行少许修补,然后绕过异常发生的地方继续执行。
    • 用别的数据进行计算,以代替方法预计会返回的值。
    • 把当前运行环境下能做的事情尽量做完,然后把相同的异常重抛到更高层。
    • 把当前运行坏境下能做的事情尽量做完,然后把不同的异常抛到更高层。
    • 终止程序。
    • 进行简化。(如果你的异常模式使问题变得太复杂,那用起来会非常痛著也很烦人)
    • 让类库和程序更安全。(这既是在为调试做短期投资,也是在为程序的健壮做长期投资)
  • 相关阅读:
    四个例子实战讲解.htaccess文件rewrite规则(转)
    unserialize反序列化错误的解决办法
    tp框架--------where("1")
    jq 鼠标点击跳转页面后 改变点击菜单的样式代码
    jq不懂的地方
    js产生随机数的几个方法
    js邮箱,汉字,数字 表单验证
    js&jQ判断checkbox表单是否被选中
    绝对好用Flash多文件大文件上传控件
    CKeditor从Word粘贴格式问题
  • 原文地址:https://www.cnblogs.com/lanqingyu/p/12357665.html
Copyright © 2011-2022 走看看