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

第十二章  通过异常处理错误(中)

12.4 创建自定义异常

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

class SimpleException extends Exception { }

public class InheritingException {
    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!");
        }
    }
}

输出结果为:

Throw SimpleException from f()

Caught it!

  编译器创建了默认构造器,他将自动调用基类的默认构造器。上面的例子的结果被打印在控制台上,但是我们也许想通过写入System.err而将错误发送给标准错误流,通常这比把错误信息输出到System.out要好,因为System.out也许会被重定向,如果发送到System.errr他就不会随着System.out一起被重定向,这样更容易被用户注意。

  也可以为异常类定义一个接受字符串参数的构造器:

package com.example.demo.exceptions;

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

public class FullConstructors {
    public static void f() throws MyException {
        System.out.println("Throwing MyException from f()");
        throw new MyException();
    }
    public static void g() throws MyException {
        System.out.println("Throwing MyException from g()");
        throw new MyException("Originated in g()");
    }
    public static void main(String[] args) {
        try {
            f();
        } catch (MyException e) {
            e.printStackTrace(System.out);
        }
        try {
            g();
        } catch (MyException e) {
            e.printStackTrace(System.out);
        }
    }
}

输出结果为:

Throwing MyException from f()

com.example.demo.exceptions.MyException

at com.example.demo.exceptions.FullConstructors.f(FullConstructors.java:11)

at com.example.demo.exceptions.FullConstructors.main(FullConstructors.java:19)

Throwing MyException from g()

com.example.demo.exceptions.MyException: Originated in g()

at com.example.demo.exceptions.FullConstructors.g(FullConstructors.java:15)

at com.example.demo.exceptions.FullConstructors.main(FullConstructors.java:24)

12.4.1 异常与记录日志

  你可能还想使用java.util.logging工具将输出记录到日志中:

package com.example.demo.exceptions;

import java.util.logging.*;
import java.io.*;

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 LoggingExceptions {
    public static void main(String[] args) {
        try {
            throw new LoggingException();
        } catch (LoggingException e) {
            System.err.println("Caught " + e);
        }
        try {
            throw new LoggingException();
        } catch (LoggingException e) {
            System.err.println("Caught " + e);
        }
    }
}

输出结果为:

10月 05, 2019 7:36:51 下午 com.example.demo.exceptions.LoggingException <init>

严重: com.example.demo.exceptions.LoggingException

at com.example.demo.exceptions.LoggingExceptions.main(LoggingExceptions.java:18)

Caught com.example.demo.exceptions.LoggingException

10月 05, 2019 7:36:51 下午 com.example.demo.exceptions.LoggingException <init>

严重: com.example.demo.exceptions.LoggingException

at com.example.demo.exceptions.LoggingExceptions.main(LoggingExceptions.java:23)

Caught com.example.demo.exceptions.LoggingException

  静态的Logger.getLogger方法创建了一个String参数相关联的Logger对象,这个Logger对象会将其输出发送到System.err,向Logger写入的最简单方式就是直接电泳与日志记录消息的级别相关联的方法,这里用的是severe()。为了产生日志记录消息,我们需要使用重载的printStackTrace()方法,他接受一个java.io.StringWriter对象传递给这个PrintWriter的构造器,那么通过调用toString()方法,就可以将输出抽取为一个String。

12.5 异常说明

  Java鼓励人们把方法可能会抛出的异常告知使用此方法的客户端程序员,这是种优雅的做法,他使得调用者能确切知道写什么样的代码可以捕获所有潜在的异常,当然如果提供了源代码,客户端程序员可以在源代码中查找throw语句来获知相关信息,然而程序库通常并不与源代码一起发布,为了预防这样的问题,Java提供了相应的语法,使你能以礼貌的方式告知客户端程序员某个方法可能会抛出的异常类型,然后客户端程序员就可以进行相应的处理,这就是异常说明。它属于方法声明的一部分,紧跟在形式参数列表之后。

  异常说明使用了副驾的关键字throws,后面接一个所有潜在异常类型的列表,所以方法定义可能看起来就像是这样:

  void f() throws TooBig, TooSmall, DivZero {  //...   }

  但是要这样子写:

  void f() {  //...  }

  就表示这个方法不会抛出任何异常,除了从RuntimeException继承的异常。

12.6 捕获所有异常

  可以只写一个异常处理程序来捕获所有类型的异常,通过捕获异常类型的、基类Exception,就可以做到这一点,事实上还有其他的基类,但Exception是同编程活动相关的基类:

catch(Exception e) {

  System.out.println(“Caught an exception”);

}

  这将捕获所有异常,所以最好把它放在处理程序列表的末尾,以防它抢在其他处理程序之前先把异常捕获了。因为Exception是与编程有关的所有异常类的基类,所以它不会含有太多具体的信息,不过可以调用它从基类Throwable继承的方法:

  String getMessage()

  String getLocalizedMessage()

  用来获取详细信息,或用本地语言表示的详细信息。

12.6.1 栈轨迹

  printStackTrace()方法所提供的信息可以通过getStackTrace方法来直接访问,这个方法将返回一个由栈轨迹中的元素所构成的数组,其中每一个元素都表示栈中的一帧。元素0是栈顶元素,并且是调用序列中的最后一个方法调用,数组中的最后一个元素和栈底是调用序列中的第一个方法调用,下面是一个简单的演示示例:

public class WhoCalled {
    static void f() {
        try {
            throw new Exception();
        } catch (Exception e) {
            for(StackTraceElement ste : e.getStackTrace())
                System.out.println(ste.getMethodName());
        }
    }
    static void g() { f(); }
    static void h() { g(); }
    public static void main(String[] args) {
        f();
        System.out.println("--------------------");
        g();
        System.out.println("--------------------");
        h();
    }
}

输出结果为:

f

main

--------------------

f

g

main

--------------------

f

g

h

main

12.6.2 重新抛出异常

  又是希望把刚捕获的异常重新抛出,尤其是在使用Exception捕获所有异常的时候,既然已经得到了对当前异常对象的引用,可以直接把它重新抛出:

  catch(Exception e) {

    System.out.println(“An exception was thrown”);

  }

  重抛异常会把异常抛给上一级环境的异常处理程序,同一个try块的后续catch子句将被忽略,此外,异常对象的所有信息都得到保持,所以高一级环境中捕获此异常的处理程序可以从这个异常对象中得到所有信息。

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

package com.example.demo.exceptions;

public class Rethrowing {
    public static void f() throws Exception {
        System.out.println("originating the exception in f()");
        throw new Exception("thrown from f()");
    }
    public static void g() throws Exception {
        try {
            f();
        } catch (Exception e) {
            System.out.println("Inside g().e.printStackTrace()");
            e.printStackTrace(System.out);
            throw e;
        }
    }
    public static void h() throws Exception {
        try {
            f();
        } catch (Exception e) {
            System.out.println("Inside h().e.printStackTrace()");
            e.printStackTrace(System.out);
            throw (Exception)e.fillInStackTrace();
        }
    }
    public static void main(String[] args) {
        try {
            g();
        } catch (Exception e) {
            System.out.println("main:printStackTrace()");
            e.printStackTrace(System.out);
        }

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

输出结果为:

originating the exception in f()

Inside g().e.printStackTrace()

java.lang.Exception: thrown from f()

at com.example.demo.exceptions.Rethrowing.f(Rethrowing.java:6)

at com.example.demo.exceptions.Rethrowing.g(Rethrowing.java:10)

at com.example.demo.exceptions.Rethrowing.main(Rethrowing.java:28)

main:printStackTrace()

java.lang.Exception: thrown from f()

at com.example.demo.exceptions.Rethrowing.f(Rethrowing.java:6)

at com.example.demo.exceptions.Rethrowing.g(Rethrowing.java:10)

at com.example.demo.exceptions.Rethrowing.main(Rethrowing.java:28)

originating the exception in f()

Inside h().e.printStackTrace()

java.lang.Exception: thrown from f()

at com.example.demo.exceptions.Rethrowing.f(Rethrowing.java:6)

at com.example.demo.exceptions.Rethrowing.h(Rethrowing.java:19)

at com.example.demo.exceptions.Rethrowing.main(Rethrowing.java:35)

main:printStackTrace()

java.lang.Exception: thrown from f()

at com.example.demo.exceptions.Rethrowing.h(Rethrowing.java:23)

at com.example.demo.exceptions.Rethrowing.main(Rethrowing.java:35)

原文地址:https://www.cnblogs.com/parable/p/11625638.html

时间: 2024-11-07 01:36:24

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

《JAVA编程思想》学习笔记——第十二章 通过异常处理错误

Java的基本理念是 "结构不佳的代码不能运行" 发现错误的理想时机是在编译阶段,也就是在你试图运行程序之前.然而,编译期间并不能找出所有的错误,余下的问题必须在运行期间解决.这就需要错误源能通过某种方式,把适当的信息传递给某个接收者----该接收者将知道如何正确处理这个问题. 异常情形是指阻止当前方法或作用域继续执行的问题. 当抛出异常后,有几件事会随之发生.首先,同Java中其它对象的创建一样,将使用new在堆上创建异常对象.然后,当前的执行路径被终止,并且从当前环境中弹出对异常对

java编程思想读书笔记 第十二章 通过异常处理错误(下)

1.异常的限制 当覆盖方法的时候,只能抛出在基类方法的异常说明里列出的那些异常.这意味着,当基类使用的代码应用到其派生类对象的时候,一样能够工资,异常也不例外. 下面的例子是在编译时施加在异常上面的限制: public class BaseBallException extends Exception {} public class Foul extends BaseBallException{} public class Strike extends BaseBallException{} p

Java编程思想学习(十二) 数组和容器

一.数组 1).数组的多种初始化方式 下面总结了初始化数组的多种方式,以及如何对指向数组的引用赋值,使其指向另一个数组对象.值得注意的是:对象数组和普通数组的各种操作基本上都是一样的:要说有什么不同的话就是对象数组默认值为null,而基本数组视本身情况而定. 1 package lkl; 2 3 import java.util.Arrays; 4 5 ///下面演示了数组的初始化 6 //包括对象数组和普通数组 7 class Base{ 8 private static long count

Java编程思想之十二 通过异常处理错误

Java的基本概念是结构不佳的代码不能运行余下的问题必须在运行期间解决,这就需要错误源能通过某种方式,把适当的信息传递给某个接收者--该接收者将知道如何正确处理这里问题. 12.1 概念 使用异常所带来的另一个相当明显的好处,它往往能够降低错误处理代码的复杂度. 12.2 基本异常 异常情形是指阻止当前方法或作用域继续执行的问题.把异常情形与普通问题相区分很重要,普通问题是指,在当前环境下能得到足够的信息,总能处理这个错误.而对于异常情形,就不能继续下去了,因为在当前环境下无法获得必要的信息来解

第十二章 通过异常处理错误

1,system.out,与system.err的区别 大多数操作系统都有三个标准文件描述符:标准输入,标准输出,标准出错. 三个操作系统的文件描述符映射到编程语言的标准库中,往往加了一层包装,但是名字通常还是叫标准输入,标准输出,标准出错. 在其它语言中的一般写法是:stdin,stdout,stderr(有的语言里大写,有的语言里小写).对应Java中的System.in,System.out,System.err. 在语言层面的实现三个文件描述符都是可以重定向的(只要你想).但是一般而言,

java编程思想总结(二)

java编程思想总结(二) java编程思想总结是一个持续更新的系列,是本人对自己多年工作中使用到java的一个经验性总结,也是温故而知新吧,因为很多基础的东西过了这么多年,平时工作中用不到也会遗忘掉,所以看看书,上上网,查查资料,也算是记录下自己的笔记吧,过一段时间之后再来看看也是蛮不错的,也希望能帮助到正在学习的人们,本系列将要总结一下几点: 面向对象的编程思想 java的基本语法 一些有趣的框架解析 实战项目的整体思路 代码的优化以及性能调优的几种方案 整体项目的规划和视角 其它遗漏的东西

JAVA编程思想(2) - 操作符(二)

5. 直接常量 -一般来说,如果程序里使用了"直接常量",编译器可以准确的知道要生成什么样的类型,但有时候却是模棱两可的.这时候需要我们对编译器进行适当的"指导" -直接常量后面的后缀字符标示了它的类型. -指数记数法:e代表"10的幂次" -注意如果编译器能够正确的识别类型,就不必在数值后附加字符,例如语句: float f4 = 200; 不存在含糊不清的地方,所以200后面不需要加L,但是对于:float f4 = 1e-43f; 编译器通

“全栈2019”Java多线程第四十二章:获取线程与读写锁的保持数

难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多线程第四十二章:获取线程与读写锁的保持数 下一章 "全栈2019"Java多线程第四十三章:查询是否有线程在等待读写锁 学习小组 加入同步学习小组,共同交流与进步. 方式一:关注头条号Gorhaf,私信"Java学习小组". 方式二:关注公众号Gorhaf,回复&quo

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

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