Java编程思想 学习笔记12
十二、通过异常处理错误
Java的基本理念是“结构不佳的代码不能运行”。
Java中的异常处理的目的在于通过使用少于目前数量的代码来简化大型、可靠的程序的生成,并且通过这种方式可以使你更加自信:你的程序中没有未处理的错误。
1.概念
C以及其他早期语言常常具有多种错误处理模式,这些模式往往建立在约定俗成的基础上,而并不属于语言的一部分。通常会返回某个特殊值或者设置某个标志,并且假定接收者将对这个返回值或标志进行检查,以判定是否发生了错误。然而,对于构造大型、健壮、可维护的程序而言,这种错误处理模式已经成为了主要障碍。
解决的办法是,用强制规定的形式来消除错误处理过程中随心所欲的因素。这种做法由来已久,对异常处理的实现可以追溯到20世纪60年代的操作系统,甚至于BASIC语言中的on error goto语句。而C++的异常处理机制基于Ada,Java中的异常处理则建立在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参数的构造器,分别是Error、Exception和RuntimeException。如果要把其他类型的异常链接起来,应该使用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的更多相关文章
- [Java编程思想-学习笔记]第3章 操作符
3.1 更简单的打印语句 学习编程语言的通许遇到的第一个程序无非打印"Hello, world"了,然而在Java中要写成 System.out.println("He ...
- Java编程思想 学习笔记1
一.对象导论 1.抽象过程 Alan Kay曾经总结了第一个成功的面向对象语言.同时也是Java所基于的语言之一的Smalltalk的五个基本特性,这些特性表现了纯粹的面向对象程序设计方式 1)万物皆 ...
- [Java编程思想-学习笔记]第1章 对象导论
1.1 抽象过程 Java是一门面向对象的语言,它的一个优点在于只针对待解问题抽象,而不用为具体的计算机结构而烦心,这使得Java有完美的移植性,也即Java的口号"Write Once, ...
- Java编程思想 学习笔记11
十一.持有对象 通常,程序总是根据运行时才知道的某些条件去创建新对象.在此之前,不会知道所需对象的数量,甚至不知道确切的类型. Java实用库还提供了一套相当完整的容器类来解决这个问题,其中基本的类 ...
- Java编程思想 学习笔记10
十.内部类 可以将一个类的定义放在另一个类的定义内部,这就是内部类. 内部类是一种非常有用的特性,因为它允许你把一些逻辑相关的类组织在一起,并控制位于内部的类的可视性.然而必须要了解,内部类和组合是 ...
- Java编程思想学习笔记——类型信息
前言 运行时类型信息(RTTI:Runtime Type Information)使得我们可以在程序运行时发现和使用类型信息. Java在运行时识别对象和类的信息的方式: (1)一种是RTTI,它假定 ...
- Java编程思想 学习笔记7
七.复用类 1.组合语法 在新的类中产生现有类的对象.由于新的类是由现有类的对象所组成,所以这种方法叫做组合. 类中域为基本类型时能够自动被初始化为零.对象引用被初始化为null. 编译器不是简单地为 ...
- Java编程思想 学习笔记5
五.初始化与清理 1.用构造器确保初始化 在Java中,通过提供构造器,类的设计者可确保每个对象都会得到初始化.创建对象时,如果其类具有构造器,Java就会在用户有能力操作对象之前自动调用相应的构造 ...
- Java编程思想 学习笔记4
四.控制执行流程 1.true和false 所有条件语句都利用条件表达式的真或假来决定执行路径.注意Java不允许我们将一个数字作为布尔值使用. 2.if-else 3.迭代 while.do-whi ...
随机推荐
- SpringMvc常见问题汇总
1.Service类未用@Service注解2016-10-26 17:31:36 [org.springframework.web.context.ContextLoader]-[ERROR] Co ...
- Comparer Under Centos 7
Kompare 效果还行.
- python之tkinter使用举例-Button
tkinter用于编写GUI界面,python3默认已经包含,直接使用. # GUI:tkinter使用举例 import tkinter # 实例化tkinter对象 top = tkinter.T ...
- Lodop打印控件里SET_PRINT_STYLE和SET_PRINT_STYLEA
LODOP.SET_PRINT_STYLE 对该语句后面的打印项样式设置效果.LODOP.SET_PRINT_STYLEA 针对第一个参数设置的打印项样式设置效果.这两个语句,作用范围不同. 在设置字 ...
- vander范德蒙德行列式
https://baike.baidu.com/item/%E8%8C%83%E5%BE%B7%E8%92%99%E8%A1%8C%E5%88%97%E5%BC%8F function m=vande ...
- Nginx ACCESS阶段 如何限制IP访问
192.168.1.0/24(最大32位的子网掩码) 每个ip是8位 那么 24/8 = 3 也就是前三个二进制 是 11111111 11111111 11111111 是指子网掩码的位数.写的是多 ...
- 计算机cpu、寄存器、内存区别
1.寄存器是中央处理器内的组成部份.它跟CPU有关.寄存器是有限存贮容量的高速存贮部件,它们可用来暂存指令.数据和位址.在中央处理器的控制部件中,包含的寄存器有指令寄存器(IR)和程序计数器(PC). ...
- Luogu4238 【模板】多项式求逆(NTT)
http://blog.miskcoo.com/2015/05/polynomial-inverse 好神啊! B(x)=B'(x)·(2-A(x)B'(x)) 注意ntt的时候防止项数溢出,即将多项 ...
- Java8 使用
Java8 使用 链接:https://www.jianshu.com/p/936d97ba0362 链接:https://www.jianshu.com/p/41de7b5ac7b9 本文主要总结了 ...
- Python Matplot中文显示完美解决方案
原因与现象 Matplot是一个功能强大的Python图表绘制库,很遗憾目前版本自带的字体库中并不支持中文字体.所以如果在绘制内容中需要显示中文,那么就会显示为方格字符. 解决办法 有一个较为完美的解 ...