`
href
  • 浏览: 7789 次
  • 性别: 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块忽略它将会导致程序在遇到错误的情况下悄然的执行下去。正确的处理异常能够避免无可挽回的失败。

分享到:
评论

相关推荐

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

    MySQL中的异常处理是数据库编程中不可或缺的一部分,它允许开发者预设对可能出现的错误或异常的响应,从而确保程序的稳定性和健壮性。在MySQL中,异常定义和处理主要是通过`DECLARE`语句来实现的。 1. **异常定义**...

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

    《使用蒙特卡洛方法进行异常值剔除的MATLAB实践》 在数据分析领域,异常值的处理是一项至关重要的任务,因为异常值可能对统计分析和模型构建产生显著影响。蒙特卡洛模拟(Monte Carlo Simulation)是一种广泛应用的...

    异常值剔除matlab_异常值剔除程序_异常值_异常值剔除

    异常值在数据分析中是一个重要的概念,它通常指的是与数据集中其他观测值显著不同的数值。在统计分析、机器学习以及各种领域研究中,异常值可能由于测量错误、数据录入错误或其他异常情况导致,如果不进行处理,可能...

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

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

    android开发,异常处理,捕获异常上传到bugly,捕获异常库module

    在Android应用开发中,异常处理是一项至关重要的任务,它确保了程序在遇到错误时能够以适当的方式响应,而不是突然崩溃。本项目聚焦于如何在Android应用程序中有效地捕获异常,并将其上传到Bugly这一第三方错误追踪...

    易语言HOOK异常处理

    "New_SE_Handler"可能是一个新的结构化异常处理程序,结构化异常处理(SEH)是Windows操作系统中的一个特性,用于处理硬件和软件异常。 "GetSeAddr"可能是获取异常发生时的地址函数,这对于分析异常原因和定位问题...

    程序崩溃异常捕获

    在软件开发过程中,异常捕获是一项至关重要的技术,它能够帮助开发者及时发现并解决程序运行时出现的问题。当用户在使用应用时遇到错误导致程序崩溃,如果没有适当的异常处理机制,用户体验将大大降低,同时,开发者...

    易语言线程结构异常处理

    在易语言中,线程是并发执行的程序单位,线程结构异常处理是编程过程中非常重要的一环,因为线程可能会遇到各种异常情况,如内存访问错误、除零异常等。 线程结构异常处理源码是易语言中处理这些异常的关键部分。当...

    c/vc++/MFC异常处理/结构化异常处理 浅析

    在编程领域,异常处理是确保程序健壮性与稳定性的关键技术。对于C、C++以及基于MFC(Microsoft Foundation Classes)的开发来说,异常处理更是不可或缺的一部分。本篇文章将深入浅析C、C++中的异常处理机制以及MFC中...

    计算布格异常Fortran程序

    在地球物理领域,布格异常(Bouguer Anomaly)是重力测量中的一个重要概念,它是自由空气异常经过地形改正后的结果。本程序主要针对的是利用Fortran语言编写的一个计算布格异常的程序,旨在处理地形数据和自由空气...

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

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

    详解SpringCloud Finchley Gateway 统一异常处理

    详解 SpringCloud Finchley Gateway 统一异常处理 SpringCloud Finchley Gateway 统一异常处理是指在使用 SpringCloud Finchley 版本的 Gateway 时,如何统一处理系统级异常的方法。默认情况下,SpringCloud ...

    android全局异常捕获 exception_global

    在Android开发中,全局异常捕获是一个至关重要的实践,它能确保应用在遇到未预期的错误时仍能保持稳定,并提供良好的用户体验。标题"android全局异常捕获 exception_global"和描述都指向了这个主题,表明我们将探讨...

    java异常处理习题

    Java 异常处理习题 Java 异常处理是 Java 编程语言中的一种重要机制,用于处理程序在运行时可能出现的错误或异常情况。下面是关于 Java 异常处理的习题和知识点总结: 一、Java 异常处理关键字 * Java 中用来抛出...

    异常检测常用的一些数据集

    异常检测在IT行业中是至关重要的一个领域,尤其是在数据挖掘和机器学习中,它涉及到网络安全、工业设备故障预测、金融欺诈检测、医疗诊断等多个方面。以下是一些常用的异常检测数据集,以及它们各自的特点和可能的...

    异常处理 异常处理 异常处理

    异常处理是编程中的一种机制,用于捕获和处理运行时发生的错误或异常情况。异常可以由硬件引发,如硬件异常,也可以由操作系统或应用程序自身触发,即软件异常。当异常发生时,操作系统允许程序有机会检查异常类型并...

    java 自定义异常实例二

    在Java编程语言中,异常处理是一项关键特性,它允许程序员优雅地处理程序运行时可能出现的错误情况。自定义异常是Java异常处理的一部分,允许我们创建符合特定业务需求的异常类。下面我们将深入探讨Java自定义异常...

    异常值的类型及其处理方法

    ### 异常值的类型及其处理方法 #### 异常值概述 异常值是指在数据集中与其他观测值相比显著偏离的数据点。这类数据点往往暗示着由不同的机制生成。异常值检测是数据挖掘中的一个重要环节,它对于数据分析、模型...

    地下介质密度异常的反演实验.docx

    地下介质密度异常的反演实验 地球物理反演是一门研究地球内部介质物理状态的空间变化及物性结构的科学分支。它通过地球表面观测到的物理现象来推测地球内部介质物理状态的空间变化及物性结构。地球物理反演的应用...

    java异常机制小结

    Java 异常机制的基础知识包括异常的基础概念、异常的分类、异常的对象、异常的来源、异常的处理等几个方面。 一、Java 异常的基础知识 异常是程序中的一些错误,但并不是所有的错误都是异常,并且错误有时候是可以...

Global site tag (gtag.js) - Google Analytics