1.异常的限制

当覆盖方法的时候,仅仅能抛出在基类方法的异常说明里列出的那些异常。

这意味着,当基类使用的代码应用到其派生类对象的时候,一样能够工资,异常也不例外。

以下的样例是在编译时施加在异常上面的限制:

public class BaseBallException extends Exception {}
public class Foul extends BaseBallException{}
public class Strike extends BaseBallException{}
public abstract class Inning {
public Inning() throws BaseBallException{}
public void event() throws BaseBallException{}
public abstract void addBat()throws Strike,Foul;
public void walk() {}
}
public class StormException extends Exception{}
public class RainedOut extends StormException{}
public class PopFoul extends Foul{}
public interface Storm {
public void event() throws RainedOut;
public void rainHard() throws RainedOut;
}
public class StromMyInnerings extends Inning implements Storm{
/**
* @throws BaseBallException
*/
public StromMyInnerings() throws RainedOut,BaseBallException {}
public StromMyInnerings(String s)throws RainedOut,BaseBallException{}
/**
* @throws RainedOut
*/
@Override
public void rainHard() throws RainedOut {}
/**
* @throws Strike
*/
@Override
public void addBat() throws PopFoul {}
public void event(){}
public static void main(String[] args) {
StromMyInnerings stromMyInnerings;
try {
stromMyInnerings = new StromMyInnerings();
stromMyInnerings.addBat();
} catch (RainedOut e) {
System.out.println("RainedOut");
} catch (PopFoul e) {
System.out.println("PopFoul");
} catch (BaseBallException e) {
System.out.println("BaseBallException");
}
Inning inning;
try {
inning = new StromMyInnerings();
inning.addBat();
} catch (Strike e) {
System.out.println("Strike");
} catch (Foul e) {
System.out.println("Foul");
} catch (RainedOut e) {
System.out.println("RainedOut");
} catch (BaseBallException e) {
System.out.println("BaseBallException");
}
}
}

在Inning类中,能够看到构造器和event()方法都声明将抛出异常,但实际上没有抛出。

这样的方式使你能强制用户去捕获可能在覆盖后的event()版本号中添加的异常,所以它非常合理。这对于抽象方法相同成立,如addBat()。

接口Storm值得注意,由于它包括了一个在Inning中定义的方法event()和一个不在Inning中定义的方法rainHard()。

这两个方法都抛出新的异常RainedOut。

假设StromMyInnerings类在扩展Inning类的同事又出现了Storm接口,那么Storm里的event()方法就不能改变Inning中的event()方法的异常接口。

否则的话,在使用基类的时候就不能推断是否捕获了正常的异常。当然,假设接口里定义的方法不是来自于基类。比方rainHard(),那么此方法抛出什么样的异常都没有问题。

异常限制对构造器不起作用,你会发现StromMyInnerings的构造器能够抛出不论什么异常。而不必理会基类构造器所抛出的异常。

派生类构造器不能捕获基类构造器抛出的异常。

虽然在继承过程中,编译器会对异常说明做强制要求。但异常说明本身并不属于方法类型的一部分。方法类型是由方法的名字与參数的类型组成的。因此。不能基于异常说明来重载方法。

此外。一个出如今基类方法的异常。不一定会出如今派生类方法的异常说明里。换句话说,在继承和覆盖的过程中。某个特定方法的“异常说明的接口”不是变大了而是变小了–这恰好和类接口在继承时的情形相反。

2.构造器

假设一个类继承了某个类同一时候又实现了某个接口,他们有相同的接口方法,但都抛出了不同的捕获性异常,则该子类实现与重写该方法时,则方法声明处不能抛出不论什么捕获性异常了。

假设调用的父类构造器抛出捕获性异常。则子类对应的构造器也仅仅能抛出。不能在构造器里进行捕获。构造器抛出异常时正确的清理方式:比方在构造器中打开了一个文件,清理动作仅仅有在对象使用完毕而且用户调用了特殊的清理方法之后才干得以清理,而不能直接在构造器里的finally块上关闭,由于finally块是无论是否有异常都会关闭,而构造器执行成功能外界须要这个文件流。

但假设在文件成功打开后才抛出异常,则须要关闭文件,并向外界抛出异常信息:

public class InputFile {
private BufferedReader in;
public InputFile(String fname) throws Exception{
try {
in = new BufferedReader(new FileReader(fname));
} catch (FileNotFoundException e) {
System.out.println("could not open "+fname);
throw e;
}catch (Exception e) {
try {
in.close();
} catch (IOException e1) {
System.out.println("in.close() unsuccessful");
throw e;
}finally{
}
}
}
public String getLine(){
String s;
try {
s=in.readLine();
} catch (IOException e) {
throw new RuntimeException("readLine() failed");
}
return s;
}
public void dispose(){
try {
in.close();
System.out.println("dispose() successful");
} catch (IOException e) {
throw new RuntimeException("in.close() failed");
}
}
public class CleanUp {
public static void main(String[] args) {
try {
InputFile inputFile = new InputFile("D:/workspace/testjava/src/com/test/CleanUp.java");
try {
String s;
int i = 1;
while ((s = inputFile.getLine()) != null) {
}
} catch (Exception e) {
System.out.println("caught Exception in main");
e.printStackTrace(System.out);
}finally{
inputFile.dispose();
}
} catch (Exception e) {
System.out.println("InputFile construction failed");
}
}
}

InputFile 的构造器接受字符串作为參数。该字符串表示所要打开的文件名称。

在try块中,会使用此文件名称建立了FileReader对象。FileReader对象本身用处并不大,但能够用它来建立BufferedReader对象。注意。使用InputFile 的优点就是把两步操作合二为一。这样的通用的清理习惯使用方法在构造器不抛出不论什么异常时也应该运用,其基本规则是:在创建须要清理的对象之后,马上进入一个try-finally语句块。

3.异常匹配

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

查找的时候并不要求抛出的异常处理程序所声明的异常全然匹配。

派生类的对象也能够匹配其基类的处理程序,样例例如以下:

public class Annoyance extends Exception{}
public class Sneeze extends Annoyance{}
public class Human {
public static void main(String[] args) {
try {
throw new Sneeze();
} catch (Sneeze e) {
System.out.println("catch Sneeze");
}catch (Annoyance e) {
System.out.println("catch Annoyance");
}
try {
throw new Sneeze();
}catch (Annoyance e) {
System.out.println("catch Annoyance exception");
}
}
}

Sneeze异常会被第一个匹配的catch自居补货。也就是程序里的第一个。

然而假设将这个catch字句删掉,仅仅留下Annoyance的catch子句,该横向仍然能正常执行,由于这次补货的是Sneeze的基类。换句话说。catch(Annoyance e)会捕获Annoyance以及全部从它派生的异常。

假设把捕获基类的catch子句放在最前面,以此想把派生类的异常全给“屏蔽”掉,就像这样:

try {
throw new Sneeze(); }catch (Annoyance e) {
//...
} catch (Sneeze e) {
//.....
}

这样编译器就会发现Sneeze的catch子句永远也得不到执行。因此会报错。

4.其它的可选方式

异常处理的一个重要的原则是“仅仅有在你知道怎样处理的情况下才捕获异常”。实际上,异常处理的一个重要目标就是把错误处理的代码同发生错误的地点相分离。

这使你能在一段代码中专注于要完毕的事情。至于怎样处理错误,则放在还有一段代码中。

这样以来,主干代码就不会与错误处理逻辑混在一起,也更easy理解和维护。

“被检查的异常”可能使问题变得复杂,由于它们强制你在可能还没有准备优点理错误的时候被迫加上cacth子名,即使我们不知道怎样处理的情况下,这就导致了异常的隐藏:

try{
//… throw …
}catch(Exception e){//什么都不做
}

把“被检查的异常”转换为“不检查的异常”:当在一个普通方法里调用别的方法时,要考虑到“我不知道该怎样处理这个异常,可是也不能把它‘吞’了,或者仅仅打印一些没用的消息”。

JDK1.4的异常链提供了一种新的思路来解决问题。能够直接把“被检查的异常”包装进RuntimeException里面:

try{
//… throw 检查异常…
}catch(IDontKnowWhatToDoWithThisCheckedException e){
Throw new RuntimeException(e);
}

假设想把“被检查的异常”这样的功能“屏蔽”掉的话,上面是一个好的办法。不用“吞”掉异常,也不必把它放到方法的异常声明里面。而异常链还能保证你不会丢失不论什么原始异常的信息。

你还能够在“知道怎样处理的地方”来处理它,也能够其它上层catch里通过 throw e.getCause(); 再次抛出原始的“被检查的异常”。

5.异常使用指南

应该在以下情况使用异常:

1)在恰当的级别处理问题。(在知道该怎样处理的情况下才捕获异常。



2)解决问题而且又一次调用产生异常的方法。

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

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

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

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

7)终止程序。

8)进行简化。

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

6.总结

异常时java程序设计不可切割的一部分。假设不了解 怎样使用它们,那你仅仅能完毕非常有限的工作。异常处理的有点之中的一个就是它使得你能够在某处集中精力处理你要解决的问题,而在还有一边处理你编写的这段代码中产生的错误。

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

  1. 《Java编程思想》笔记 第十二章 通过异常处理错误

    1.异常也是对象 标准异常类都有两个构造器,一个默认,一个接受字符串. 抛异常与方法返回类型不同,但有相似效果使当前方法退出并返回,抛异常可以看作是一种不同的返回机制.(异同点不必深究) Throwa ...

  2. 《Java编程思想》笔记 第十九章 枚举类型

    1.基本enum特征 所有创建的枚举类都继承自抽象类 java.lang.Enum; 一个枚举类,所有实例都要在第一句写出以 ,隔开. 如果只有实例最后可以不加 : 枚举类因为继承了Enum,所以再不 ...

  3. 《Java编程思想》笔记 第十六章 数组

    1 数组 数组和容器比较,数组的优点也只剩访问效率高这一点了. 2 数组是第一级对象 数组也是一个对象,和其他普通对象一样在堆中创建, int[ ] arr  arr是数组的引用. 可以隐式创建数组对 ...

  4. 《Java编程思想》笔记 第十五章 泛型

    1 泛型 “泛型”意思就是适用于许多类型. 使用泛型的目的之一: 指定容器持有什么类型,让编译器确保正确性,而不是在运行期发现错误. 这个容器可以看成是有其他类型对象作为成员的类,而不单单只是JDK中 ...

  5. 《Java编程思想》笔记 第十四章 类型信息

    1.RTTI:在运行时识别一个对象类型 JAVA在运行时 有时要 识别对象和类的信息这个机制叫RTTI.Java提供了两种机制去做这件事.传统的RTTI 和 反射. 传统的RTTI  假定编译时就已经 ...

  6. Java编程思想读书笔记_第7章

    final关键字类似const: import java.util.*; public class FinalData { static Random rand = new Random(47); f ...

  7. Java编程思想读书笔记_第6章

    如何创建一个包: 比如创建一个包名为com.huawei 则在一个目录下如(d:\java)创建目录com/huawei 然后在huawei目录下创建一个文件Assist.java package c ...

  8. Java编程思想读书笔记_第三章

    本章提到的关于==的部分,一个完整的实验如下: class Test { public static void main(String[] args) { Integer i = new Intege ...

  9. Java编程思想读书笔记_第8章

    覆盖私有方法 class Father { private void f() { System.out.println("Father::f()"); } public stati ...

随机推荐

  1. [Oracle] oracle统计信息

    Oracle统计信息 Oracle数据库里的统计信息可以分为6种类型: 表的统计信息 索引的统计信息 列的统计信息 系统统计信息 数据字典统计信息 内部对象统计信息 图 1: Oracle统计信息 基 ...

  2. 去掉VS中的警告错误:warning C4819

    当项目引用到外部源代码后,经常出现4819错误,警告信息如下: warning C4819: 该文件包含不能在当前代码页(936)中表示的字符.请将该文件保存为 Unicode 格式以防止数据丢失. ...

  3. Java接口中的成员变量的意义

    转自:http://blog.csdn.net/ameyume/article/details/6189749 在interface里面的变量都是public static final 的.所以你可以 ...

  4. ObjectInputStream&ObjectOutputStream工具类

    序列化:将数据保存到文件:ObjectOutputStream; 反序列化:将文件中的数据显示出来:ObjectInputStream;   在反序列化程序中运行后能够正常输出Person的相关信息, ...

  5. Fiddler抓包3-查看get与post请求【转载】

    本篇转自博客:上海-悠悠 原文地址:http://www.cnblogs.com/yoyoketang/p/6719717.html 前言 前面两篇关于Fiddler抓包的一些基本配置,配置完之后就可 ...

  6. python的tips:字符和字符串的问题

    今天,自己建立了一个redis,python去访问的时候, 设置可以key以后,再读取key,返回的是字符, 和字符串比较,需要做一个转换, 信息如下: import redisr=redis.Red ...

  7. ***七牛跨域上传图片JS SDK

    SDK: http://developer.qiniu.com/code/v6/sdk/javascript.html#upload 上传 在页面中引入 plupload,plupload.full. ...

  8. js-限制参与活动的范围(微信H5活动)

    近期接到大连某个项目,一个H5的活动,其中有一个需求就是:这个活动的参与者仅限大连地区的用户 所以参考了微信API 得出的操作结果为: wx.ready(function() { wx.getLoca ...

  9. UVA 1151 Buy or Build MST(最小生成树)

    题意: 在平面上有n个点,要让所有n个点都连通,所以你要构造一些边来连通他们,连通的费用等于两个端点的欧几里得距离的平方.另外还有q个套餐,可以购买,如果你购买了第i个套餐,该套餐中的所有结点将变得相 ...

  10. Spring bean初始化以及管理

    在完成bean实例化后,spring会根据配置文件的设定情况对bean 的属性进行初始化, 1.autowire方式 (可查找自动装配对象 但bean中要有相应属性的set方法)这是一个自动装配的机制 ...