第十二章 迷迷糊糊的异常(二)

一、异常与记录日志

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.logging.Logger;

class LoggingException extends Exception{
    private static Logger logger = Logger.getLogger("LoggingException");
    public LoggingException() {
        StringWriter trace = new StringWriter();
        printStackTrace(new PrintWriter(trace));
        logger.severe(trace.toString());
    }
}
public class Demo6 {
    public static void main(String[] args) {
        try {
            throw new LoggingException();
        }catch(LoggingException e) {
            System.err.println("Caught " + e);
        }
    }
}

输出结果:

二、栈轨迹

public class Demo7 {

    void f1() throws Exception {
        throw new Exception();
    }
    void f2()throws Exception { f1(); }
    void f3()throws Exception { f2(); }
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        try {
            Demo7 d = new Demo7();
            d.f3();
        }catch(Exception e) {
            for(StackTraceElement s : e.getStackTrace()) {
                System.out.println(s);
            }
        }
    }

}

输出结果:

结果说明:getStackTrace()此方法返回轨迹栈中的元素StackTraceElement所构成的数组,轨迹栈中的每一栈帧即为一层函数的调用。(同虚拟机栈中的栈帧)。

三、重新抛出异常

实例一:异常对象的消息内容与在那一层方法处理异常无关

public class Demo8 {

    void f() {
        try {
            throw new Exception("My Exception");
        }catch(Exception e) {
            e.printStackTrace();
        }
    }
    void g() { f(); }
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Demo8 d = new Demo8();
        d.f();
    }

}

输出结果:

结果说明:异常对象消息内容和异常处理地点的无关性,轨迹栈的栈底永远都是main();

实例二:fillInStackTrace()重新抛出带有新消息的异常

public class Demo9 {

    void f() throws Exception {
        throw new Exception("from f()");
    }
    //抛出原来的异常
    void g() throws Exception {
        try {
            f();
        }catch(Exception e) {
            System.out.println("g(), e.printStackTrace():");
            e.printStackTrace(System.out);
            throw e;
        }
    }
    //将原来的异常填入当前调用栈消息,并覆盖原有消息
    void h() throws Exception {
        try {
            f();
        }catch(Exception e) {
            System.out.println("f(), e.printStackTrace():");
            e.printStackTrace(System.out);
            //这里throw类似方法调用,fillInStackTrace()返回Throwable类
            throw (Exception)e.fillInStackTrace();
        }
    }
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Demo9 d = new Demo9();
        try {
            d.g();
        }catch(Exception e) {
            System.out.println("main() e.printStackTrace()");
            e.printStackTrace(System.out);
        }

        try {
            d.h();
        }catch(Exception e) {
            System.out.println("main() e.printStackTrace()");
            e.printStackTrace(System.out);
        }
    }

}

输出结果:

结果说明:fillInStackTrace()方法将当前异常抛出点方法调用栈的信息覆盖原来抛出点调用栈信息。

四、异常链

异常链:在捕获一个异常后抛出另外一个异常,并把原始异常的信息保存下来。

使用情形:一般在构造器中处理异常,都会另外再抛出一个异常,因为不想让调用方误以为对象被成功的建立。不过尽量不要编写抛出异常的构造器,编码会比较麻烦,应该让对象尽快安全的被初始化和建立。

实例一:

public class Demo10 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Demo10 d = new Demo10();
        try {
            d.test();
        }catch(Exception e) {
            e.printStackTrace();
        }
    }

    void test() {
        try {
            int i = 10/0;
        }catch(Exception e) {
            throw new RuntimeException(e);
        }
    }

}

输出结果:

结果说明:像这样直接使用构造器接受cause的类,只有Error、Exception、RuntimeException。其它类型需要使用initCause()方法连接。实际上,异常类的绝大部分方法都是从Throwable继承而来的。

实例二:

import java.io.IOException;

class MyException extends Exception{}

public class Demo11 {

    static void test() throws MyException{
        try {
            throw new IOException();
        }catch(Exception e) {
            MyException m = new MyException();
            m.initCause(e);
            throw m;
        }
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        try {
            test();
        }catch(Exception e) {
            e.printStackTrace();
        }
    }

}

输出结果:

结果说明:调用initCause()惯例,要么在创建异常的时候马上调用,要么在异常的构造器中调用。

实例三:“被检查异常”包装成“不受检查的异常”

public class Demo13 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        try {
            test();
        }catch(Exception e) {
            e.printStackTrace();
            try {
                throw (Exception)e.getCause();
            }catch(Exception e1) {
                System.out.println("getCause():");
                e1.printStackTrace();
            }

        }
    }

    static void test() {
        try {
            throw new Exception();
        }catch(Exception e) {
            throw new RuntimeException(e);
        }
    }

}

输出结果:

结果说明:getCause()方法望文知意,是用来获取Cause的,并返回Throwable类。

五、异常丢失

实例:

public class Demo12 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        try {
            throw new RuntimeException();
        }finally {
            return;
        }
    }

}

结果说明:部分代码不会抛出任何异常,但是会有警告:finally模块没有正常编译。

六、异常的限制

1、覆盖方法时,只能够抛出基类方法异常说明里的异常。(可以是异常说明里异常的子类)这样不影响某些共用代码。

2、如果继承的或者实现的类,有同名方法,在进行覆盖时,要取throws声明的子集。

3、在进行向上转型时,用基类引用调用方法时要捕获基类此方法的异常,应为编译器根本就不清楚基类引用的实际类型,所以通不过编译。

实例:

import java.io.IOException;

class A {
    void print() throws IOException {
            System.out.println("A");
            throw new IOException();
    }
}
public class Demo12 extends A{

    void print() {
        System.out.println("Demo12");
    }
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        try {
            A a = new Demo12();
            a.print();
        }catch(Exception e) {
            e.printStackTrace();
        }

    }

}

输出结果:

Demo12

原文地址:https://www.cnblogs.com/mgblogs/p/11412333.html

时间: 2024-10-20 00:51:00

第十二章 迷迷糊糊的异常(二)的相关文章

【读书笔记】C#高级编程 第十六章 错误和异常

(一)简介 错误的出现并不总是编写应用程序的人的原因,有时应用程序会因为应用程序的最终用户引发或运行代码的环境而发生错误.C#提供了异常处理机制来处理错误. (二)异常类 在C#中,但刚出现某个特殊的异常错误条件时,就会创建(或抛出)一个异常对象.一般情况下异常没有特定的名称空间,异常类应放在生成异常的类所在的名称空间. (三)捕获异常 .NET Framework提供了大量的预定义基类异常对象.为了在C#代码中处理可能的错误情况,一般要把程序的相关部分分成3种不同类型的代码块. try块包含的

C++ Primer Plus学习:第十五章

第十五章 友元.异常和其他 友元 友元类 表 0-1 class Tv { public: friend class Remote; } Remote类可以使用Tv的数据成员,Remote类在Tv类后定义 . 友元成员函数 表 0-2 class Tv; //前向声明 class Remote { public: void chanup(Tv &t); } class Tv { public: friend void Remote::set_chan(Tv& t, int c); } 异常

第十二章 读书笔记

第十二章  Linux 驱动程序中的 阻塞和非阻塞 I/O 等待队列是 Linux 内核的一种实现进程休眠的技术.在上一章介绍的自旋锁使用的是不断循环 的方式阻塞 Linux 驱动,这种方式很占 CPU 资源.而等待队列的你眠技术可以大大降低休眠进程对 CPU 资源的消耗,信号量就是利用等待队列实现了对临界区的锁定.本节将介绍等待队列的原 理以及相关的函数和宏,最后会使用一个完整的例子来演示如何使用等待队列休眠和唤醒进程. 运行在用户空间的应用程序可以使用 select函数检测设备文件是否可以读

Java学习笔记—第十二章 Java网络编程入门

第十二章  Java网络编程入门 Java提供的三大类网络功能: (1)URL和URLConnection:三大类中最高级的一种,通过URL网络资源表达方式,可以很容易确定网络上数据的位置.利用URL的表示和建立,Java程序可以直接读入网络上所放的数据,或把自己的数据传送到网络的另一端. (2)Socket:又称"套接字",用于描述IP地址和端口(在Internet中,网络中的每台主机都有一个唯一的IP地址,而每台主机又通过提供多个不同端口来提供多种服务).在客户/服务器网络中,当客

[CSAPP笔记][第十二章并发编程]

第十二章 并发编程 如果逻辑控制流在时间上是重叠,那么它们就是并发的(concurrent).这种常见的现象称为并发(concurrency). 硬件异常处理程序,进程和Unix信号处理程序都是大家熟悉的例子. 我们主要将并发看做是一种操作系统内核用来运行多个应用程序的机制. 但是,并发不仅仅局限于内核.它也可以在应用程序中扮演重要的角色. 例如 Unix信号处理程序如何允许应用响应异步事件 例如:用户键入ctrl-c 程序访问虚拟存储器的一个未定义的区域 其他情况 访问慢速I/O设备 当一个应

第十二章类的无参方法

一.javaDoc注释: 语法:/** * *@author FLC */ 生成javaDoc文档的步骤:点击File--Export--展开java文件夹--选择javaDoc--点击Next--制定生成doc文档的文件位置--点击Fish--找到生成文件位置查看. 二.类中的方法: 语法:   访问修饰符  方法返回值类型  方法名称(){} 例如: public void run(){ } public String ball(){ } String ball="球"; retu

第十二章随笔

第十二章,Android下综合项目介绍之一 随着社会电子信息化的不断发展,人们在居家中实验的电器越来越多,由此带来的安全隐患也越来越多,为了减少电器的不合理使用带来的异常情况,由此带来的安全隐患也有了明显的增多,为了减少电器的不合理使用带来的异常情况,就要求在异常发生时用户及时能得到消息,并通过实时监控采取一定的操作排除异常,因此 远程监控系统的作用是非常大的.仅用浏览器可观看,同事还具有以下优点.布控局域广阔,嵌入式视频WEB服务器监控系统WEB服务器直接连人网络,没有线缆长度和信号衰减的限制

Java编程思想---第十二章 通过异常处理错误(中)

第十二章  通过异常处理错误(中) 12.4 创建自定义异常 我们不必拘泥于Java中已有的异常类型,Java提供的异常体系不可能预见所有的错误,所以可以自己定义异常类来表示程序中可能会遇到的特定问题:要自己定义异常类,必须从已有的异常类继承,最好是选择意思相近的异常类继承,建立新的异常类最简单的方法就是让编译器为你产生默认构造器,所以这几乎不用写多少代码: class SimpleException extends Exception { } public class InheritingEx

C和指针 (pointers on C)——第十二章:使用结构和指针

第十二章 使用结构和指针 这章就是链表.先单链表,后双向链表. 总结: 单链表是一种使用指针来存储值的数据结构.链表中的每个节点包含一个字段,用于指向链表的下一个节点. 有一个独立的根指针指向链表的第1个节点.单链表只能从一个方向遍历. 如何insert单链表:1.新节点的link字段必须设置为指向它的后面节点.2.前一个节点的link字段必须指向这个新节点. 为了防止可能会插入链表的起始位置这种情况,在C中,可以保存一个指向必须进行修改的link字段的指针,而不是保存一个指向前一个节点的指针.