`
href
  • 浏览: 7549 次
  • 性别: Icon_minigender_1
  • 来自: 福建
最近访客 更多访客>>
社区版块
存档分类
最新评论
阅读更多
第39条:只针对不正常的条件才使用异常
try{
int i=0;
while(true)
a[i++].f();
}catch(ArrayIndexOutOfBoundsException e){

}
三个错误:
1.异常机制的设计初衷是用于不正常的情形,所以很少会有jvm实现试图对它们的性能做优化。所以,创建,抛出和捕获异常的开销是昂贵的。
。2.把代码放在try-catch块中反而阻止了现代jvm实现本来可能执行的某些特定的优化。
3.对数组进行遍历的标准模式并不会导致冗余的检查,有些现代的jvm实现会将它们优化掉。

基于异常的循环不仅模糊了代码的意图,降低了它的性能,而且它不能保证正常工作。

异常只应该被用于不正常的条件,它们永远不应该被用于正常的控制流。更一般的,你应该优先使用标准的,容易理解的模式,而不是那些声称可以提供更好性能的,弄巧成拙的模式。即使真的能够改进性能,面对jvm实现的不断改进,这种模式的性能优势也许不复存在。然而,由这种过渡聪明的模式带来的隐藏的错误,以及维护的痛苦却依然存在。

一个设计良好的api不应该强迫它的客户为了正常的控制流而使用异常。如果一个类具有一个状态相关的方法,即只有特定的不可预知的条件下才可以被调用的方法,那么这个类往往也应该有一个单独的状态测试方法,即只是是否可以调用第一个方法。例如,Iterator类有一个状态相关的next方法,它返回迭代过程中的下一个元素,对应的状态测试方法为hasNext。这使得使用标准模式称为可能。

第40条:对于可恢复的条件使用被检查的异常,对于程序错误使用运行时异常。
java提供三种可抛出结构:被检查的异常,运行时异常,和错误。

主要的原则是:如果期望调用者能够恢复,那么对于这样的条件应该使用被检查的异常。

有两种未被检查的可抛出结构:运行时异常和错误。在行为上两者是等同的;他们都是不需要也不应该被捕获的抛出物。如果一个程序抛出一个未被检查的异常或者一个错误,则往往是不可恢复的情形,继续执行下去有害无益。如果一个程序没有捕获这样的可抛出结构,将会导致当前线程停止,并伴以一个适当的错误消息。

用运行时异常来指明程序错误。大多数的运行时异常都是表明前提违例。所谓前提违例是指api的客户没有遵守api规范建立的约定。

你所实现的所有的为被检查的抛出结构都应该是RuntimeException的子类(直接或间接的)、最好不要实现Error子类。

总而言之,一般对于可恢复的条件使用被检查时异常,对于程序错误,使用运行时异常。

第41条:避免不必要的使用被检查的异常。
被检查的异常是java的一个很好特性,于返回代码不同,它强迫程序员处理例外的条件,大大提高了可靠性。然而,过分使用被检查的异常会使api用起来非常不方便。如果一个方法会抛出一个或者多个被检查的异常,那么调用该方法的代码必须在一个或者多个catch块中处理异常或则声明这些异常,以便让它们传播出去,无论哪个方法都给程序员添加了不可忽视的负担。

把被检查的异常变成未被检查的异常是一种技术是,把这个要抛出异常的方法分成2个方法,其中第一个方法返回一个boolean,表明是否应该抛出异常。例如:
try{
  obj.action(args);
}catch(){

}
转化为:
if(obj.actionPermitted(args)){
  obj.action(args);
}else{

}
这种转化并不是总是合适的,但是合适的地方,总会让api用起来更舒服。虽然后者调用序列没有前者漂亮,但是这样得到的api更加灵活。如果一个对象将会在缺少外部同步的情况下被并发访问,或者可被外界改变状态,那么这种状态是不合适的,因为在actionPermitted和action这两个调用的时间间隔中,对象状态有可能发生变化。


第42条:尽量使用标准的异常
重用现有的异常有很多好处
1.最主要的是,它使得你的api更加易于学习和使用,因为它与程序原来已经熟悉的习惯用法一致。
2。对于用到这些api的程序而言,他们的可读性更好,因为他们不会冲刺着程序员不熟悉的异常。
3.异常类越少,意味着内存占用越小,并且装载这些类的时间开销也越小。

最后,一定要清楚,选择重用哪一个异常并不总是一门精确的科学。


第43条:抛出的异常要适合于相应的抽象
高层的实现应该铺货底层的异常,同时抛出一个可以按照高层抽象进行解释的异常。这种做法被称为异常转译。例子:
try{

}catch(LowerLevelException e){
  throw new HigherLevelexception();
}

一种特殊形式的异常转译被称为异常连接,如果底层的异常对于调用该异常被抛出的情形非常有帮助,那么使用异常连接是很适合的。在这种方法中,底层的异常被高层的异常保存起来,并且高层的异常提供一个公有的访问方法来获得底层的异常:
try{

}catch(LowerLevelException e){
  throw new HigherLevelexception(e);
}

尽管异常转意比不加选择的传递底层异常的做法有所改进,但是它不能被滥用。如果可能的话,处理来自底层异常的最好做法是,在调用底层方法之前确保它们会成功执行,而避免它们会抛出异常。有时候,你可以在给底层传递实参之前,显示的检查这些实参的有效性,从而避免底层方法抛出异常。

如果无法阻止来自底层的异常,那么其次做法是让高层来处理这些异常,从而将高层方法的调用者于底层的问题隔离开。

如果既不能阻止来自底层的异常,也无法将它们与高层隔离开,那么一般做法是使用异常转译。只有在底层方法的规范碰巧可以保证它抛出的异常对于高层也是合适的情况下,才可以将异常从底层传播到高层。


第44条:每个方法抛出的异常都要有文档
描述一个方法所抛出的异常,是正确使用这个方法所需要文档的重要组成部分,因此,花点时间仔细的为每个方法抛出的异常做文档是特别重要的。

总是要单独的声明被检查的异常,并且利用javadoc的@throws标记,准确的记录下每个异常被抛出的条件。如果一个方法可能会抛出多个异常类,则不要使用“快捷方式”,即声明它会抛出这些异常类的某个超类。作为一个极端的例子,永远不要声明一个方法throws exception。这样的声明不仅没有为该程序员提供关于这个方法能够抛出哪些异常的任何指导信息,而且大大的妨碍了该方法的使用,因为它实际上掩盖了在同样的执行环境中该方法可能会抛出的任何其他异常。

使用javadoc的@throws标签记录下一个方法可能会抛出的每个未被检查的异常,但是不要使用throws关键字将未被检查的异常包含在方法声明中。

如果一个类中的许多方法出于同样的原因而抛出同一个异常,那么在该类的文档注释中对这个异常做文档,而不是为每个方法单独做文档,这是可以接受的。

第45条:在细节消息中包含失败--捕获信息
为了捕获失败,一个异常的字符串表示应该包含所有对该异常有的贡献的参数和域的值。

为了确保在异常的字符串表示包含足够的失败--捕捉信息,一种办法是在异常的构造函数中以参数形式引入这些信息。然后,有了这些信息,只要把它们放到消息描述中,就可以自动产生消息细节描述。

第46条:努力使失败保持原子性
一般而言,一个失败的方法调用应该使对象保持它在被调用之前的状态。具有这种属性的方法被称为具有失败原子性。

有几种途径可以获得这种效果。最简单的办法莫过于设计一个非可变的对象,如果一个对象是非可变的,那么失败原子性是显然的。如果一个操作失败了,它可能会阻止创建新的对象,但是永远也不会使已有的对象保持在不一致的状态中,因为当每个对象被创建之后它就处于一致的状态中,以后不会再发生变化。

对于在可变对象上执行操作的方法,获得失败原子性最常见的方法是,在执行操作之前检查参数的有效性。这可以使得在对象的状态被修改之前,适当的异常首先被抛出来。
public Object pop(){
  if(size==0)
   throw new EmptyStackException();
   Object result=elements[--size];
   elements[size]=null;
   return result;
}

一种类似的获得失败原子性的办法是,对计算处理过程调整顺序,使得任何可能失败的计算部分都发生在对象状态被修改之前。如果对实参的检查只有执行了一部分计算之后才能进行的话,那么这种办法实际上是一种办法的自然扩展。

第三种获得失败原子性的办法没有那么常用,做法是编写一段恢复代码,由它来解释操作过程中发生的失败,以及使对象回滚到操作开始之前的状态上。这种办法主要用于永久性的数据结构。

最后一种获得失败原子性的办法是,在对象的一份临时拷贝上执行操作,当操作完成之后再把临时拷贝中的结果复制给原来的对象。如果数据被保存在临时的数据结构中,计算过程会更加快速,那么这种办法非常实用。

虽然失败原型总是期望的目标,但它并不是总是可以做的到。

即使在可以实现失败原子性的场合,它也并不总是所期望的。对于某些操作,它会显著的增加开销或者复杂性。然而一旦你知道了问题所在,那么获得失败原子性往往是简单而容易的。总结一条规则:作为方法规范的一部分,任何一个异常都不应该改变对象调用该方法之前的状态。如果这条规则被违反,则api文档应该清楚的指明对象将会处于什么样的状态,不幸的是,大量现在的api文档都未能做到这一点。

第47条:不要忽略异常
空的catch块会使异常达不到应有的目的,异常的目的是强迫你处理不正常的条件。至少catch块也应该包含一条说明,用来解释为什么忽略掉这个异常是合适的。

本条目中的建议同样适用于被检查的异常和未被检查的异常,不管一个异常代表了一个可遇见的例外条件,还是一个程序错误,用一个空的catch块忽略它将会导致程序在遇到错误的情况下悄然的执行下去。正确的处理异常能够避免无可挽回的失败。

分享到:
评论

相关推荐

    使用Spring AOP对异常进行统一处理

    我们在捕获到异常并对异常进行处理时可能会遇到如下一些问题: 1.不确定应如何处理这些异常 2.需要记录异常日志时没有记录,或者异常在不同的地方重复记录,使得排错调试不方便 3.处理日志时,需要在每一个try-catch...

    Spring Cloud Gateway的全局异常处理

    Spring Cloud Gateway的全局异常处理 Spring Cloud Gateway中的全局异常处理不能直接用@ControllerAdvice来处理,通过跟踪异常信息的抛出,找到对应的源码,自定义一些处理逻辑来符合业务的需求。 网关都是给接口做...

    利用java filter 实现业务异常拦截源码

    我们在做项目中肯定都会遇到自定义业务异常 ,然后将业务异常信息跳转的统一的信息提示页面的情况,比如我们在struts的时候我们会用到struts的异常处理机制,我们在业务层会跑出我们遇到业务处理异常 ,然后交由...

    dubbo捕获自定义异常_dubbo异常捕获_dubbo异常_自定义异常_捕捉异常_

    解决dubbo接口自定义异常的捕捉问题,dubbo消费者可以捕捉到提供者所抛出的自定义异常。

    CAN异常检测——logbert实现

    将bert应用于CAN总线的异常检测,具体的实现为LogBert,一种基于Bert的日志检测算法。资源中包含logbert的论文原文和源码,以及修改后适配了CAN数据的异常检测算法,准确率和召回率可达99%以上,所用数据集为韩国...

    C和C++中的异常处理

    1.异常和标准 C 对它的支持 2. Microsoft 对异常处理方法的扩展 3. 标准 C++异常处理的基本语法和语义 4. 实例剖析 EH 5. C++的 new 和 delete 操作时的异常处理 6. Microsoft 对于的实现版本中的异常处理 7. 部分...

    C# WINFORM应用程序未处理异常的统一处理技巧

    异常处理是每个应用程序都会用到的,纵然在程序编写期间我们都会最大限度的考虑可能发生的异常并进行相应的处理,但是往往并不能完全考虑周全,百密一疏,出现未处理异常而导致程序出错,数据丢失,如用户输入错误...

    精讲RestTemplate自定义请求失败异常处理.docx

    异常抛出之后,程序后面的代码就执行不到了,无法进行后面的代码执行。实际的业务开发中,有的时候我们更期望的结果是:不管你服务端是超时了还是服务不存在,我们都应该获得最终的请求结果(HTTP请求结果状态400、...

    公共场所异常人群检测

    读取公共区域的监控视频,当区域内的人群出现异常行为时,作出预警。 异常情况1:在禁止滞留区大量聚集人群(比如政府机关门口)。 异常情况2:人们突然向某一区域聚集。 2.采用的技术路线: 政府机关门口少量人聚集...

    金蝶K3清除用户异常信息

    金蝶K3清除用户异常信息工具:用于解决某些情况下个别用户操作报错或缓慢等异常情况,清理后台用户信息表。在安装了K/3客户端的电脑上运行,选择用户登陆、清理即可,不用记SQL语句、不用登陆服务器,操作方便快捷。...

    MySQL定义异常和异常处理详解

    主要为大家详细介绍了MySQL定义异常和异常处理,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

    Qt mingw release版异常结束 crash信息捕捉和跟踪(含测试代码)

    程序在debug可以正常运行,但是在release版后异常结束,系统又没有提供任何信息情况下,或者程序发布后在客户手中出现异常崩溃,但自己测试又不能复现问题,要是能捕获到异常时相关信息就很好定位问题了。...

    均匀分布下的异常数据检验

    针对样本数据服从均匀分布时,样本中出现异常数据的检验问题,利用假设检验的基本原理和方法,在顺序统计量的基础上构造了检验功效较好的检验统计量,研究了均匀分布下的异常数据检验.根据顺序统计量的一些分布性质,推导...

    两数计算+异常处理

    课程作业,实现两数计算及其异常处理,异常处理机制能让程序在异常发生时,按照代码的预先设定的异常处理逻辑,针对性地处理异常,让程序尽最大可能恢复正常并继续执行,且保持代码的清晰。 Java中的异常可以是函数...

    异常测试培训PPT,带你解锁测试过程中的异常测试

    异常测试是软件测试的一种类型,目的是验证系统在遇到各种异常或非正常情况时的表现和反应。在真实的生产环境中,由于各种原因(如人为操作失误、输入错误、硬件故障等),系统可能会遇到意外情况,这些异常情况可能...

    MonteCarlo.rar_Monte Carlo_剔除异常值_异常值_异常样本剔除_蒙特卡洛 异常

    是用于解决剔除样本异常值的蒙特卡洛mtlab代码,可以进行参考

    第7章 异常处理机制

    第7章 异常处理机制第7章 异常处理机制第7章 异常处理机制第7章 异常处理机制第7章 异常处理机制第7章 异常处理机制第7章 异常处理机制第7章 异常处理机制第7章 异常处理机制第7章 异常处理机制第7章 异常处理机制第...

    C#异常处理总结及简单实例

    C#异常处理总结及简单实例 一、异常处理的理解? 异常处理是指程序在运行过程中,发生错误会导致程序退出,这种错误,就叫做异常。 因此处理这种错误,就称为异常处理。 二、异常处理如何操作? C# 异常处理时建立在...

    JAVA实验十一 异常处理与集合类

    1、 为SavingsAccount类和CheckingAccout类的取款行为分别定义异常类NotEnoughBalanceException和OverdraftLimitExceededException,当SavingsAccount类中取款超过余额或者当CheckingAccount类产生透支超过最大额度...

    异常处理-简单的除法运算器

    3. 两个加数分别输入字符a和b,调试并修改程序,在结果文本框中输出相应的异常提示,如图3所示。 图3 格式化异常 4. 两个加数分别输入123456789876543和1,调试并修改程序,在结果文本框中输出相应的异常提示。 5. ...

Global site tag (gtag.js) - Google Analytics