十二、通过异常处理错误 

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

Java中的异常处理的目的在于通过使用少于目前数量的代码来简化大型、可靠的程序的生成,并且通过这种方式可以使你更加自信:你的程序中没有未处理的错误。

1.概念

  C以及其他早期语言常常具有多种错误处理模式,这些模式往往建立在约定俗成的基础上,而并不属于语言的一部分。通常会返回某个特殊值或者设置某个标志,并且假定接收者将对这个返回值或标志进行检查,以判定是否发生了错误。然而,对于构造大型、健壮、可维护的程序而言,这种错误处理模式已经成为了主要障碍。

  解决的办法是,用强制规定的形式来消除错误处理过程中随心所欲的因素。这种做法由来已久,对异常处理的实现可以追溯到20世纪60年代的操作系统,甚至于BASIC语言中的on error goto语句。而C++的异常处理机制基于AdaJava中的异常处理则建立在C++的基础之上。

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

  

2.基本异常

  异常情形是指阻止当前方法或作用域继续执行的问题。把异常情形与普通问题相区分很重要,所谓的普通问题是指,在当前环境下能得到足够的信息,总能处理这个错误。而对于异常情形,就不能继续下去了,因为在当前环境下无法获得必要的信息来解决问题。你所能做的就是从当前问题跳出,并且把问题提交给上一级环境。这就是抛出异常时所发生的事情。

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

  ①异常参数

  所有标准异常类都有两个构造器:一个是默认构造器;另一个是接受字符串作为参数,以便能把相关信息放入异常对象的构造器。

  通常,异常对象中仅有的信息就是异常类型,除此之外不包含任何有意义的内容。

3.捕获异常

  要明白异常是如何被捕获的,必须首先理解监控区域的概念。它是一段可能产生异常的代码,并且后面跟着处理这些异常的代码。

  ①try块

  如果在方法内部抛出了异常,这个方法将在抛出异常的过程中结束。要是不希望方法就此结束,可以在方法内设置一个特殊的块来捕获异常。因为在这个块里“尝试”各种方法调用,所以称为try块。

try {
//Here's the code
}

  ②异常处理程序 

  异常处理程序紧跟在try块后面,以关键字catch表示。

4.创建自定义异常

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

  对异常来说,最重要的部分就是类名。

5.异常说明 

  异常说明属于方法声明的一部分,紧跟在形式参数列表之后。

6.捕获所有的异常 

  可以只写一个异常处理程序来捕获所有类型的异常。通过捕获异常类型的基类Exception就可以做到这一点。

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

  异常链

  常常会想要在捕获一个异常后抛出另一个异常,并且希望把原始异常的信息保存下去,这被称为异常链。现在所有的Throwable的子类在构造器中都可以接受一个cause对象作为参数。这个cause就用来表示原始异常,这样通过把原始异常传递给新的异常,使得即使在当前位置创建并抛出了新的异常,也能通过这个异常链追踪到异常最初发生的位置。

  只有三种基本的异常类提供了带cause参数的构造器,分别是ErrorExceptionRuntimeException。如果要把其他类型的异常链接起来,应该使用initCause()方法而不是构造器。

  

7.Java标准异常 

  Throwable这个类被用来表示任何可以作为异常被抛出的类。Throwable对象可分为两种类型:Error用来表示编译时和系统错误;Exception是可以被抛出的基本类型。Java程序员关心的基类型通常是Exception。

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

  ①特例:RuntimeException 

  运行时异常会自动被Java虚拟机抛出,被称为“不受检查异常”。

  如果RuntimeException没有被捕获而直达main(),那么在程序退出前将调用异常的printStackTrace()方法。

  RuntimeException代表的是编程错误:

  1)无法预料的错误。例如null引用

  2)作为程序员,应该在代码中进行检查的错误。

8.使用finally进行清理 

  无论try块中的异常是否被抛出,finally子句里的代码总能运行。

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

  当涉及break和continue语句的时候,finally子句也会得到执行。

  当用某些特殊的方式使用finally子句,会出现异常丢失的情况。例如在finally子句中return。

9.异常的限制

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

  异常限制对构造器不起作用。但派生类构造器的异常说明必须包含基类构造器的异常说明。派生类构造器不能捕获基类构造器抛出的异常。

  不能基于异常说明来重载方法。一个出现在基类方法的异常说明中的异常,不一定会出现在派生类方法的异常说明中。

10.构造器 

  对于在构造阶段可能会抛出异常,并且要求清理的类,最安全的使用方式是使用嵌套的try子句。

11.异常匹配

  抛出异常的时候,异常处理系统会按照代码的书写顺序找出“最近”的处理程序。找到匹配的处理程序之后,它就认为异常将得到处理,查找不再继续。

  派生类的对象也可以匹配其基类的处理程序。

12.异常使用指南 

  1)在恰当的级别处理问题。

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

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

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

  5)把当前运行环境下能做的事情尽量做完,然后把相同或不同的异常抛到更高层。

  6)终止程序。

  7)进行简化。

  8)让类库和程序更安全。

13.总结   以上简略了许多内容,许多更复杂一些的问题不是一言两语。

  异常可以帮助我们制造出更多健壮的程序,是相当重要又不那么复杂的知识。应该熟练掌握

Java编程思想 学习笔记12的更多相关文章

  1. [Java编程思想-学习笔记]第3章 操作符

    3.1  更简单的打印语句 学习编程语言的通许遇到的第一个程序无非打印"Hello, world"了,然而在Java中要写成 System.out.println("He ...

  2. Java编程思想 学习笔记1

    一.对象导论 1.抽象过程 Alan Kay曾经总结了第一个成功的面向对象语言.同时也是Java所基于的语言之一的Smalltalk的五个基本特性,这些特性表现了纯粹的面向对象程序设计方式 1)万物皆 ...

  3. [Java编程思想-学习笔记]第1章 对象导论

    1.1  抽象过程 Java是一门面向对象的语言,它的一个优点在于只针对待解问题抽象,而不用为具体的计算机结构而烦心,这使得Java有完美的移植性,也即Java的口号"Write Once, ...

  4. Java编程思想 学习笔记11

    十一.持有对象  通常,程序总是根据运行时才知道的某些条件去创建新对象.在此之前,不会知道所需对象的数量,甚至不知道确切的类型. Java实用库还提供了一套相当完整的容器类来解决这个问题,其中基本的类 ...

  5. Java编程思想 学习笔记10

    十.内部类  可以将一个类的定义放在另一个类的定义内部,这就是内部类. 内部类是一种非常有用的特性,因为它允许你把一些逻辑相关的类组织在一起,并控制位于内部的类的可视性.然而必须要了解,内部类和组合是 ...

  6. Java编程思想学习笔记——类型信息

    前言 运行时类型信息(RTTI:Runtime Type Information)使得我们可以在程序运行时发现和使用类型信息. Java在运行时识别对象和类的信息的方式: (1)一种是RTTI,它假定 ...

  7. Java编程思想 学习笔记7

    七.复用类 1.组合语法 在新的类中产生现有类的对象.由于新的类是由现有类的对象所组成,所以这种方法叫做组合. 类中域为基本类型时能够自动被初始化为零.对象引用被初始化为null. 编译器不是简单地为 ...

  8. Java编程思想 学习笔记5

    五.初始化与清理 1.用构造器确保初始化  在Java中,通过提供构造器,类的设计者可确保每个对象都会得到初始化.创建对象时,如果其类具有构造器,Java就会在用户有能力操作对象之前自动调用相应的构造 ...

  9. Java编程思想 学习笔记4

    四.控制执行流程 1.true和false 所有条件语句都利用条件表达式的真或假来决定执行路径.注意Java不允许我们将一个数字作为布尔值使用. 2.if-else 3.迭代 while.do-whi ...

随机推荐

  1. Atlas & mysql-proxy

    Atlas https://github.com/Qihoo360/Atlas https://github.com/Qihoo360/Atlas/wiki/Installing-Atlas Atla ...

  2. Selenium自动化测试框架

    如下图所示,为公司搭建的基于Selenium+Ant+TestNG+Jenkins的持续集成的自动化测试框架. Selenium: Page Object Model+Data Driver(Exce ...

  3. MySQL乐观锁在分布式场景下的实践

    背景 在电商购物的场景下,当我们点击购物时,后端服务就会对相应的商品进行减库存操作.在单实例部署的情况,我们可以简单地使用JVM提供的锁机制对减库存操作进行加锁,防止多个用户同时点击购买后导致的库存不 ...

  4. 【转帖】intel 2018年1 月2号爆出漏洞分析 知乎匿名用户

    作者:匿名用户链接:https://www.zhihu.com/question/265012502/answer/288407097来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载 ...

  5. Bootstrap手风琴效果

    前面的话 Bootstrap 框架中 Collapse插件(折叠)其实就是我们常见的手风琴效果.当单击一个触发元素时,在另外一个可折叠区域进行显示或隐藏,再次单击时可以反转显示状态.经典的场景是多个折 ...

  6. windows常见数据类型

    一,常见数据类型 WORD:                16位无符号整形数据 DWORD:             32位无符号整型数据(DWORD32) DWORD64:         64位 ...

  7. BZOJ4551[Tjoi2016&Heoi2016]树——dfs序+线段树/树链剖分+线段树

    题目描述 在2016年,佳媛姐姐刚刚学习了树,非常开心.现在他想解决这样一个问题:给定一颗有根树(根为1),有以下 两种操作:1. 标记操作:对某个结点打上标记(在最开始,只有结点1有标记,其他结点均 ...

  8. C# 后台访问webapi

    具体在哪看见的忘记了. 异步: public static class CallWebAPI { public static async Task<string> APIPost(stri ...

  9. [模板]Link-Cut-Tree动态树

    做法以后再补,先写一些注意事项. 做法以后也不补了,直接看这个吧.https://www.cnblogs.com/candy99/p/6271344.html 1.rotate其实是最容易写错的地方( ...

  10. SimpleDateFormat是线程不安全的,切忌切忌!

    多线程方法中使用了共享变量SimpleDateFormat,报如下错误: java.lang.NumberFormatException: multiple points  at sun.misc.F ...