Java异常异常处理的几条建议

复数类实现加减乘除并处理异常 复数类实现加减乘除并处理异常,使用throw try catch和finally 立即下载

第1条: 只针对不正常的情况才使用异常

建议:异常只应该被用于不正常的条件,它们永远不应该被用于正常的控制流。
通过比较下面的两份代码进行说明。
代码1

try {
    int i=0;
    while (true) {
        arr[i]=0;
        i++;
    }
} catch (IndexOutOfBoundsException e) {
}

代码2

for (int i=0; i<arr.length; i++) {
    arr[i]=0;
}

  两份代码的作用都是遍历arr数组,并设置数组中每一个元素的值为0。代码1的是通过异常来终止,看起来非常难懂,代码2是通过数组边界来终止。我们应该避免使用代码1这种方式,主要原因有三点:
• 异常机制的设计初衷是用于不正常的情况,所以很少会会JVM实现试图对它们的性能进行优化。所以,创建、抛出和捕获异常的开销是很昂贵的。
• 把代码放在try-catch中返回阻止了JVM实现本来可能要执行的某些特定的优化。
• 对数组进行遍历的标准模式并不会导致冗余的检查,有些现代的JVM实现会将它们优化掉。

实际上,基于异常的模式比标准模式要慢得多。测试代码如下:

public class Advice1 {

    private static int[] arr = new int[]{1,2,3,4,5};
    private static int SIZE = 10000;

    public static void main(String[] args) {

        long s1 = System.currentTimeMillis();
        for (int i=0; i<SIZE; i++)
            endByRange(arr);
        long e1 = System.currentTimeMillis();
        System.out.println("endByRange time:"+(e1-s1)+"ms" );

        long s2 = System.currentTimeMillis();
        for (int i=0; i<SIZE; i++)
            endByException(arr);
        long e2 = System.currentTimeMillis();
        System.out.println("endByException time:"+(e2-s2)+"ms" );
    }

    // 遍历arr数组: 通过异常的方式
    private static void endByException(int[] arr) {
        try {
            int i=0;
            while (true) {
                arr[i]=0;
                i++;
                //System.out.println("endByRange: arr["+i+"]="+arr[i]);
            }
        } catch (IndexOutOfBoundsException e) {
        }
    }

    // 遍历arr数组: 通过边界的方式
    private static void endByRange(int[] arr) {
        for (int i=0; i<arr.length; i++) {
            arr[i]=0;
            //System.out.println("endByException: arr["+i+"]="+arr[i]);
        }
    }
}
运行结果:
endByRange time:8ms
endByException time:16ms

结果说明:通过异常遍历的速度比普通方式遍历数组慢很多!

 

第2条: 对于可恢复的条件使用被检查的异常,对于程序错误使用运行时异常

• 运行时异常     -- RuntimeException类及其子类都被称为运行时异常。
• 被检查的异常 -- Exception类本身,以及Exception的子类中除了"运行时异常"之外的其它子类都属于被检查异常。

  它们的区别是:Java编译器会对"被检查的异常"进行检查,而对"运行时异常"不会检查。也就是说,对于被检查的异常,要么通过throws进行声明抛出,要么通过try-catch进行捕获处理,否则不能通过编译。而对于运行时异常,倘若既"没有通过throws声明抛出它",也"没有用try-catch语句捕获它",还是会编译通过。当然,虽说Java编译器不会检查运行时异常,但是,我们同样可以通过throws对该异常进行说明,或通过try-catch进行捕获。
  ArithmeticException(例如,除数为0),IndexOutOfBoundsException(例如,数组越界)等都属于运行时异常。对于这种异常,我们应该通过修改代码进行避免它的产生。而对于被检查的异常,则可以通过处理让程序恢复运行。例如,假设因为一个用户没有存储足够数量的前,所以他在企图在一个收费电话上进行呼叫就会失败;于是就将一个被检查异常抛出。

 

第3条: 避免不必要的使用被检查的异常

  "被检查的异常"是Java语言的一个很好的特性。与返回代码不同,"被检查的异常"会强迫程序员处理例外的条件,大大提高了程序的可靠性。
  但是,过分使用被检查异常会使API用起来非常不方便。如果一个方法抛出一个或多个被检查的异常,那么调用该方法的代码则必须在一个或多个catch语句块中处理这些异常,或者必须通过throws声明抛出这些异常。 无论是通过catch处理,还是通过throws声明抛出,都给程序员添加了不可忽略的负担。

  适用于"被检查的异常"必须同时满足两个条件:第一,即使正确使用API并不能阻止异常条件的发生。第二,一旦产生了异常,使用API的程序员可以采取有用的动作对程序进行处理。

 

第4条: 尽量使用标准的异常

代码重用是值得提倡的,这是一条通用规则,异常也不例外。重用现有的异常有几个好处:
第一,它使得你的API更加易于学习和使用,因为它与程序员原来已经熟悉的习惯用法是一致的。
第二,对于用到这些API的程序而言,它们的可读性更好,因为它们不会充斥着程序员不熟悉的异常。
第三,异常类越少,意味着内存占用越小,并且转载这些类的时间开销也越小。

Java标准异常中有几个是经常被使用的异常。如下表格:
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ 异常                                                                  ┃ 使用场合                                                              ┃
┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
┃ IllegalArgumentException                             │ 参数的值不合适                                                    ┃
┠───────────────────────────┼─────────────────────────────┨
┃ IllegalStateException                                     │ 参数的状态不合适                                                 ┃
┠───────────────────────────┼─────────────────────────────┨
┃ NullPointerException                                      │ 在null被禁止的情况下参数值为null                     ┃
┠───────────────────────────┼─────────────────────────────┨
┃ IndexOutOfBoundsException                       │ 下标越界                                                               ┃
┠───────────────────────────┼─────────────────────────────┨
┃ ConcurrentModificationException                │ 在禁止并发修改的情况下,对象检测到并发修改 ┃
┠───────────────────────────┼──────────── ─────────────────┨
┃ UnsupportedOperationException                │ 对象不支持客户请求的方法                                   ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
  虽然它们是Java平台库迄今为止最常被重用的异常,但是,在许可的条件下,其它的异常也可以被重用。例如,如果你要实现诸如复数或者矩阵之类的算术对象,那么重用ArithmeticException和NumberFormatException将是非常合适的。如果一个异常满足你的需要,则不要犹豫,使用就可以,不过你一定要确保抛出异常的条件与该异常的文档中描述的条件一致。这种重用必须建立在语义的基础上,而不是名字的基础上!
  最后,一定要清楚,选择重用哪一种异常并没有必须遵循的规则。例如,考虑纸牌对象的情形,假设有一个用于发牌操作的方法,它的参数(handSize)是发一手牌的纸牌张数。假设调用者在这个参数中传递的值大于整副牌的剩余张数。那么这种情形既可以被解释为IllegalArgumentException(handSize的值太大),也可以被解释为IllegalStateException(相对客户的请求而言,纸牌对象的纸牌太少)。

 

第5条: 抛出的异常要适合于相应的抽象

  如果一个方法抛出的异常与它执行的任务没有明显的关联关系,这种情形会让人不知所措。当一个方法传递一个由低层抽象抛出的异常时,往往会发生这种情况。这种情况发生时,不仅让人困惑,而且也"污染"了高层API。
  为了避免这个问题,高层实现应该捕获低层的异常,同时抛出一个可以按照高层抽象进行介绍的异常。这种做法被称为"异常转译(exception translation)"。

  例如,在Java的集合框架AbstractSequentialList的get()方法如下(基于JDK1.7.0_40):

public E get(int index) {
    try {
        return listIterator(index).next();
    } catch (NoSuchElementException exc) {
        throw new IndexOutOfBoundsException("Index: "+index);
    }
}

  listIterator(index)会返回ListIterator对象,调用该对象的next()方法可能会抛出NoSuchElementException异常。而在get()方法中,抛出NoSuchElementException异常会让人感到困惑。所以,get()对NoSuchElementException进行了捕获,并抛出了IndexOutOfBoundsException异常。即,相当于将NoSuchElementException转译成了IndexOutOfBoundsException异常。

 

第6条: 每个方法抛出的异常都要有文档

  要单独的声明被检查的异常,并且利用Javadoc的@throws标记,准确地记录下每个异常被抛出的条件。
  如果一个类中的许多方法处于同样的原因而抛出同一个异常,那么在该类的文档注释中对这个异常做文档,而不是为每个方法单独做文档,这是可以接受的。

 

第7条: 在细节消息中包含失败 -- 捕获消息

  简而言之,当我们自定义异常或者抛出异常时,应该包含失败相关的信息。
  当一个程序由于一个未被捕获的异常而失败的时候,系统会自动打印出该异常的栈轨迹。在栈轨迹中包含该异常的字符串表示。典型情况下它包含该异常类的类名,以及紧随其后的细节消息。

 

第8条: 努力使失败保持原子性

  当一个对象抛出一个异常之后,我们总期望这个对象仍然保持在一种定义良好的可用状态之中。对于被检查的异常而言,这尤为重要,因为调用者通常期望从被检查的异常中恢复过来。
  一般而言,一个失败的方法调用应该保持使对象保持在"它在被调用之前的状态"。具有这种属性的方法被称为具有"失败原子性(failure atomic)"。可以理解为,失败了还保持着原子性。对象保持"失败原子性"的方式有几种:

(01) 设计一个非可变对象。
(02) 对于在可变对象上执行操作的方法,获得"失败原子性"的最常见方法是,在执行操作之前检查参数的有效性。如下(Stack.java中的pop方法):

public Object pop() {
    if (size==0)
        throw new EmptyStackException();
    Object result = elements[--size];
    elements[size] = null;
    return result;
}

(03) 与上一种方法类似,可以对计算处理过程调整顺序,使得任何可能会失败的计算部分都发生在对象状态被修改之前。
(04) 编写一段恢复代码,由它来解释操作过程中发生的失败,以及使对象回滚到操作开始之前的状态上。
(05) 在对象的一份临时拷贝上执行操作,当操作完成之后再把临时拷贝中的结果复制给原来的对象。
虽然"保持对象的失败原子性"是期望目标,但它并不总是可以做得到。例如,如果多个线程企图在没有适当的同步机制的情况下,并发的访问一个对象,那么该对象就有可能被留在不一致的状态中。

  即使在可以实现"失败原子性"的场合,它也不是总被期望的。对于某些操作,它会显著的增加开销或者复杂性。
  总的规则是:作为方法规范的一部分,任何一个异常都不应该改变对象调用该方法之前的状态,如果这条规则被违反,则API文档中应该清楚的指明对象将会处于什么样的状态。

 

第9条: 不要忽略异常

  当一个API的设计者声明一个方法会抛出某个异常的时候,他们正在试图说明某些事情。所以,请不要忽略它!忽略异常的代码如下:

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

  空的catch块会使异常达不到应有的目的,异常的目的是强迫你处理不正常的条件。忽略一个异常,就如同忽略一个火警信号一样 -- 若把火警信号器关闭了,那么当真正的火灾发生时,就没有人看到火警信号了。所以,至少catch块应该包含一条说明,用来解释为什么忽略这个异常是合适的。

  

Effective Java (异常处理) Effective Java (异常处理),需要的朋友可以参考一下 立即下载

相关推荐

RAD Studio 10.4.2 安装避坑指南:从镜像加载到首次运行的全流程解析

本文提供了一份详尽的RAD Studio 10.4.2安装避坑指南,涵盖从镜像验证、文件提取到安装激活的全流程。重点解析了安装教程中常见的权限、路径及激活顺序等关键“坑点”,旨在帮助开发者,尤其是Delphi和C++Builder新手,一次性顺利完成安装与配置,确保开发环境稳定运行。

weixin_29224309的博客 327

Java异常(二) 《Effective Java》中关于异常处理的几条建议

本章是从《Effective Java》摘录整理出来的关于异常处理的几条建议。内容包括: 第1条: 只针对不正常的情况才使用异常 第2条: 对于可恢复的条件使用被检查的异常,对于程序错误使用运行时异常 第3条: 避免不必要的使用被检查的异常 第4条: 尽量使用标准的异常 第5条: 抛出的异常要适合于相应的抽象 第6条: 每个方法抛出的异常都要有文档 第7条: 在细节消息中包含失败 -

cmz的专栏 834

VSAN数据救援实战:当26个虚拟机突然不可访问时我们做了什么?

本文深度复盘了一次由运维操作失误引发的VMware vSAN存储危机,导致26个虚拟机数据不可访问的实战救援过程。文章详细剖析了vSAN脑裂状态的诊断方法,分享了在官方支持受限时,如何结合社区智慧与自主分析,通过精准的底层命令干预和状态推理,最终成功恢复全部数据的破局思路与操作细节,为vSAN数据救援提供了宝贵经验。

weixin_35749786的博客 237

Java提高篇——Java 异常处理

异常的概念 异常是程序中的一些错误,但并不是所有的错误都是异常,并且错误有时候是可以避免的。 比如说,你的代码少了一个分号,那么运行出来结果是提示是错误java.lang.Error;如果你用System.out.println(11/0),那么你是因为你用0做了除数,会抛出java.lang.ArithmeticException的异常。 异常发生的原因有很多,通常包含以下几大类: ...

weixin_34174422的博客 690

深度学习、图像分类入门,从VGG16卷积神经网络开始

刚开始接触深度学习、卷积神经网络的时候非常懵逼,不知道从何入手,我觉得应该有一个进阶的过程,也就是说,理应有一些基本概念作为奠基石,让你有底气去完全理解一个庞大的卷积神经网络: 本文思路: 一、我认为学习卷积神经网络必须知道的几个概念: 1、卷积过程:   我们经常说卷积神经网络卷积神经网络,到底什么才是卷积?网络层卷积过程到底怎么实现?我们在这里借鉴了另一位博客大牛的动态图来给大

Errors_In_Life的博客 16万+

如何免费访问和使用Gemini API?

Gemini Ultra具有最先进的性能,在几个指标上超过了GPT-4的性能。它是第一个在大规模多任务语言理解基准测试中超越人类专家的模型,该基准测试57个不同学科的世界知识和解决问题的能力。Gemini是谷歌迄今为止开发的最先进、最庞大的AI模型。它为多模态而建,理解并处理不同类型的数据,比如文本、代码、音频、图像和视频。下面我们将加载Masood Aslami的图像,并用它来测试Gemini Pro Vision的多模态性。有了Gemini可以为查询提供图像、音频和文本,获得几乎完美的答案。

java_cjkl的博客 1万+

算数的异常处理 --- (Java版)

注:这里主要是讲解 try{}catch(){}的使用 1.为什么要讲异常,比如:当我们在进行除法运算的时候,我们规定的是分母是不能为0的,当我们面向对象的时候,如果有用户输入了 0,那么很有可能就会导致我们的系统崩溃。 2.我们通常的解决方法就是加判断语句但是这明显的效率并不高,比如:我们输入了中文,而我们算数只能是数字,所以我们无法简单第判断所有的错误,如何才能有较高的效率呢,我们Java中用了try{}catch(){}语句出来解决了我们的问题。 代码: public class d

m0_52725750的博客 1460

人形机器人硬件开发:骨架系统设计全攻略

本文以人形机器人骨架系统为核心研究对象,系统解析其从理论建模到工程实现的全流程设计方法。通过融合刚体力学、材料科学与机器人控制理论,构建"概念基础-理论框架-架构设计-实现机制-实际应用-高级考量-综合拓展"的七层分析体系。重点覆盖运动学/动力学建模、轻量化结构设计、关节模块集成、多物理场耦合优化等关键技术,结合波士顿动力Atlas、本田ASIMO等经典案例,提供从原型设计到量产验证的工程实践指南。

AI天才研究院 1878

EffectiveJava学习笔记28:异常(上)-异常的适用范围、java的三种可抛出结构、抛出与抽象对应的异常

1.只针对异常情况才使用异常 这里就是说不要将异常用于正常的控制流中。 例: try{.....}catch(Exception e){.......} 不要在抛出异常时写正常的控制代码,因为异常机制是没有jvm优化的。所以异常应该只适用于异常情况 2.java的三种可抛出结构 java语言有三种可抛出结构:受检异常、运行时异常、错误 1.受检异常就是我们平常用于ca...

沙丁鱼的博客 640

通信算法之249: DJI波形物理层

D-J-I的Lightbridge波形、Ocusync1波形、Ocusync2波形、Ocusync3波形,

leegang12的专栏 1440

基于Simulink进行光伏逆变器效率分析的仿真建模

特点能量转换:将光伏电池板产生的直流电转换为交流电。效率评估:分析逆变器在不同负载条件和环境条件下的效率。动态特性:考虑温度、光照强度等外部因素对逆变器效率的影响。挑战精确建模:准确地模拟光伏电池板、逆变器及其交互的动力学过程。多因素考量:需要同时考虑输入电压、电流、温度、光照强度等多种因素对逆变器效率的影响。集成度:需要与其他系统(如最大功率点跟踪MPPT算法、电网连接等)无缝集成,以实现全面的系统分析。首先明确要模拟的任务内容。输入条件(如光照强度、温度等)。

amy_mhd的博客 142

《Effective Java》中关于异常处理的几条建议

概要 本章是从《Effective Java》摘录整理出来的关于异常处理的几条建议。内容包括:第1条: 只针对不正常的情况才使用异常第2条: 对于可恢复的条件使用被检查的异常,对于程序错误使用运行时异常第3条: 避免不必要的使用被检查的异常第4条: 尽量使用标准的异常第5条: 抛出的异常要适合于相应的抽象第6条: 每个方法抛出的异常都要有文档第7条: 在细节消息中包含失败 -- 捕获消息第8条:...

1639

【51单片机仿真】基于51单片机设计的温湿度采集检测系统__资料编号11

该系统通过与AT89C51单片机、LCD1602显示屏和DHT11温湿度传感器的集成,实时读取环境中的温度和湿度数据并在LCD1602上显示这些信息,其中系统初始化LCD1602显示屏、通过DHT11_receive()函数接收并校验DHT11传感器的温湿度数据、使用LCD_ShowNum()函数逐位显示湿度和温度数据并在这些数据后附加相应的单位符号,以便用户可以直观地看到当前环境的温湿度情况。

嵌入式阿齐Archie 2万+

合理的使用Java异常_Java异常处理的几条建议

第1条: 只针对不正常的情况才使用异常建议:异常只应该被用于不正常的条件,它们永远不应该被用于正常的控制流。通过比较下面的两份代码进行说明。代码1:1 try{2 int i=0;3 while (true) {4 arr[i]=0;5 i++;6 }7 } catch(IndexOutOfBoundsException e) {8 }代码2:1 f...

weixin_42356145的博客 212

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

java异常体系____《Effective Java》中关于异常处理的几条建议

Java异常(二) 《Effective Java》中关于异常处理的几条建议   概要 本章是从《Effective Java》摘录整理出来的关于异常处理的几条建议。内容包括: 第1条: 只针对不正常的情况才使用异常 第2条: 对于可恢复的条件使用被检查的异常,对于程序错误使用运行时异常 第3条: 避免不必要的使用被检查的异常 第4条: 尽量使用标准的异常 第5条: 抛出的

531

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

java异常处理

什么是异常 异常处理 如何捕捉异常? finally语句 常见异常 自定义异常 那么具体如何自定义异常类呢? throw关键字 throws关键字 运行时异常 异常处理流程

随便写点C++和JAVA的知识 6302

JAVA异常处理(三种异常处理机制)

异常是程序在编译或执行的过程中可能出现的问题,语法错误不算在异常体系提前处理异常,程序会更加安全Error: 系统级别问题、JVM退出等,代码无法控制Exception: Java.lang包下,称为异常类,它表示程序本身可以处理的问题 Runtime Exception及其子类: 运行时异常,编译阶段不会报错(如空指针,数组索引越界异常) 除Runtime Exception之外所有异常:

二十多岁的你迷茫又着急,想要车子,想要房子,想要享受旅行,你那么浮躁,拿什么看透人生! 1万+

Java异常处理终结篇——如何进行Java异常处理设计

使用Java异常的人很多,但能合理使用的却不多,Java异常处理设计是一个冷门的话题,但好的异常设计会让程序有质的变化,所以本文从各个方面分析便总结了,在Java程序中,如何进行异常设计。

登高而望远 1万+

Java异常处理的十条建议

前言 Java异常处理的十个建议,希望对大家有帮助~ 一、尽量不要使用e.printStackTrace(),而是使用log打印。 反例: try{ // do what you want }catch(Exception e){ e.printStackTrace(); } 正例: try{ // do what you want }catch(Exception e){ log.info("你的程序有异常啦,{}",e); } 理由: printStackTrace()打

王国隆的技术博客 1638
上一篇: Java:java时间日期格式转换
hoyan_li
博客等级 码龄14年 5粉丝 43原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值