优雅编程之这样考虑异常,你就“正常”了(三十一)

开心一笑

【今天压力特别大,一直感觉有一种无形的力量扼住了喉咙,让我呼吸困难,脖子后面老有风。刚去了趟医院,医生认真的检查之后,告诉我:你毛衣穿反了!】

**提出问题******

项目中如何处理异常???

解决问题

励志图片

以下来自《Effective Java》这本书的笔记:

在这里复习下异常分类:

java中异常分为两类:checked exception(检查异常)和unchecked exception(未检查异常),对于未检查异常也叫RuntimeException(运行时异常).

对未检查的异常(unchecked exception )的几种处理方式:
1、捕获
2、继续抛出
3、不处理

对检查的异常(checked exception,除了RuntimeException,其他的异常都是checked exception )的几种处理方式:

1、继续抛出,消极的方法,一直可以抛到java虚拟机来处理
2、用try...catch捕获

注意,对于受检异常必须处理,或者必须捕获或者必须抛出

例如:

1)非受检的:NullPointerException,ClassCastException,ArrayIndexsOutOfBoundsException,
ArithmeticException(算术异常,除0溢出)

2)受检:Exception,FileNotFoundException,IOException,SQLException.
只针对异常的情况才使用异常

异常应该只用于异常情况下,它们永远不应该用于正常控制流中。

错误案例:

try{
    int i = 0;
    while(true){
        range[i++].climb();
        
    }
}catch(ArrayOutOfBoundsException e){
    //ArrayOutOfBoundsException 是非受检异常,不应该捕获,同时,也不应该
    //在正常代码中处理这种异常    
}

改正:

for(Mountain m:range){
    m.climb();
}

错误案例

try {
    Iterable<Foo> i = collection.iterator();
    while (true){
        Foo foo = i.next();
    }
}catch (NoSuchElementException e){
    
}

改正:

for(Iterable<Foo> i = collection.iterator();i.hasNext();){
    Foo foo = i.next();
}
对可恢复的情况使用受检异常,对编程错误使用运行时异常

标题已经说的很清楚了,下面简单描述下:

在决定使用受检的异常或是未受检的异常时,主要原则是:如果期望调用者能够适当地恢复,对于这种情况就应该使用受检的异常。

有两种未受检的可抛出结构:运行时异常和错误,它们都是不需要也不应该被捕获的可抛出结构。如果程序抛出未受检的异常或者错误,往往就属于不可恢复的情形,继续执行下去有害无益。

优先使用标准的异常

专家级程序员与缺乏经验的程序员一个最主要的区别在于,专家追求并且通常也能够实现高度的代码

代码重用是值得提倡的,这是一条通用的规则,异常也不例外。

可以这么说,所有错误的方法调用都可以被归结为非法参数或者非法状态,即IllegalArgumentException 和 IllegalArgumentException

抛出与抽象相对应的异常

异常转义:更高层的实现应该捕获底层的异常,同时抛出可以按照高层抽象进行解释的异常。

例如:

    try{
        //use lower-level abstraction to do our bidding
        ...
    }catch(LowerLevelException e){
        throw new HigherLevelException(...);
    }    

    public void uploadImageFile(String imagePath)  {

        try {
            /上传图片文件
        }catch(IOException e) {
           //把原始异常信息记录到日记中(便于排错)
            throw  new 异常构造方法();
     }
  }

异常链:将异常发生的原因一个传一个串起来,即把底层的异常信息传给上层,这样逐层抛出.

try {
     lowLevelOp();
}catch (LowLevelException le) {

     throw (HighLevelException)
      new HighLevelException().initCause(le);

}

总而言之,如果不能阻止或者处理来自更底层的异常,一般的做法是使用异常转译,除非底层方法碰巧可以保证它跑车的所有异常也适合才可以将异常从底层传播到高层。异常链对高层和底层异常都提供了最佳的功能;它允许抛出适当的高层异常,同时又能捕获底层的原因进行失败分析。

每个方法抛出的异常都要有文档

始终要单独地声明受检的异常,并且利用Javadoc的@throws标记,准确地记录下抛出每个异常的条件。

具体可以参考这篇文章:检查异常和未检查异常不同之处

总而言之,要为你编写的每个方法所能抛出的每个异常建立文档。对于未受检和受检的异常,以及对于抽象的和具体的方法都一样。要为每个受检异常提供单独的throws子句,不要为未受检的异常提供throws子句。如果没有为可以抛出的异常建立文档,其他人就很难或者根本不可能有效地使用你的类或者接口。

在细节消息中包含能捕获失败的信息

为了捕获异常,异常的细节信息应该包含所有“对该异常有贡献”的参数和域的值。

例如:

/**
 * Constructs an <code>IndexOutOfBoundsException</code> with the
 * specified detail message.
 *
 * @param   s   the detail message.
 */
//这个是IndexOutOfBoundsException这个异常的构造器
public IndexOutOfBoundsException(String s) {
    super(s);
}    

期望:

/**
 * @param lowerBound
 * @param upperBound
 * @param index
 */
//通过改造后的异常可以包含足够的能捕获失败的信息
public IndexOutOfBoundsException(int lowerBound,int upperBound,int index){
    super("Lower bound: " + lowerBound +
    ",Upper bound: " + upperBound + 
    ", Index:" + index);
    this.lowerBound = lowerBound;
    this.upperBound = upperBound;
    this.index = index;
}
努力使失败保持原子性

失败原子性:失败的方法调用应该使对象保持在被调用之前的状态。

对于可变对象上执行操作的方法,获得失败原子性最常见的办法是,在执行操作之前检查参数的有效性。这可使得在对象的状态被修改之前,先抛出适当的异常。例如:

public Object pop(){
    //如果取消对size检查,会导致size域保持不一致的状态
    if(size == 0){
        throw new EmptyStackException();
    }
    Object result = elements[--size];
    elements[size] = null;//
    return result;
}

另外一种获得失败原子性的办法是,调整计算处理过程的顺序,使得任何可能会失败的计算部分都在对象状态被修改之前发生。

最后一种获得失败原子性的办法是,在对象的一份临时拷贝上执行操作,当操作完成之后,再用临时拷贝中的结果代替对象的内容。

不要忽略异常

当API的设计者声明一个方法将抛出某个异常的时候,他们等于正在视图说明某些事情。所有请不要忽略它!

例如:

try{
    ...
}catch(SomeException e){
        
}

上面的例子中,是一个空的catch块,空的catch块会使异常达不到应有的目的,

读书感悟

来自宗白华《美学散步》

  • 中国的建筑、园林、雕塑中都潜伏着音乐感——即所谓“韵”。西方有的美学家说:一切的艺术都趋向于音乐。这话是有部分真理的。
  • 一切艺术的美,以至于人格的美,都趋向于玉的美:内部有光泽,但是含蓄的光采,这种光彩是极绚烂又极平淡。
  • 音乐领导我们去把握世界生命万千形象里最深的节奏的起伏。

其他

如果有带给你一丝丝小快乐,就让快乐继续传递下去,欢迎转载,点赞,顶,欢迎留下宝贵的意见,多谢支持!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,384评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,845评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,148评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,640评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,731评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,712评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,703评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,473评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,915评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,227评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,384评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,063评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,706评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,302评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,531评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,321评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,248评论 2 352

推荐阅读更多精彩内容

  • 第五十七条、只针对异常的情况才使用异常 不要优先使用基于异常的模式:因为异常机制的设计初衷是用于不正常的情况,所以...
    Timorous阅读 665评论 0 1
  • 通俗编程——白话JAVA异常机制 - 代码之道,编程之法 - 博客频道 - CSDN.NEThttp://blog...
    葡萄喃喃呓语阅读 3,178评论 0 25
  • 57、只针对异常的情况才使用异常 在这段代码中,当循环企图访问数组边界之外的元素时,抛出异常,以达到终止无限循环的...
    Alent阅读 307评论 0 3
  • 57,值针对异常的情况才适用异常 在现代jvm上实现上,基于异常的模式比标准模式要慢的多。 异常只能用于异常情况下...
    求闲居士阅读 383评论 0 0
  • 充分发挥异常的优点,可以提高程序的可读性、可靠性和可维护性。如果使用不当,它们会带来负面影响。 1.只针对异常的情...
    666真666阅读 260评论 0 0