我总是在错误的背景下看到Throwable / Exception.但是我可以想一下这样一种情况:扩展Throwable只是为了打破一堆递归方法调用.比如说,您试图通过递归搜索的方式在树中查找并返回一些对象.一旦你发现它坚持在一些Carrier扩展Throwable并抛出它,并在调用递归方法的方法中捕获它.

正面:您不必担心递归调用的返回逻辑;既然你找到了你需要的东西,为什么还要担心如何将这个引用备份到方法堆栈中.

否定:您有一个不需要的堆栈跟踪. try / catch块也变得违反直觉.

这是一个愚蠢的简单用法:

public class ThrowableDriver {
    public static void main(String[] args) {
        ThrowableTester tt = new ThrowableTester();
        try {
            tt.rec();
        } catch (TestThrowable e) {
            System.out.print("All good\n");
        }
    }
}

public class TestThrowable extends Throwable {

}

public class ThrowableTester {
    int i=0;

    void rec() throws TestThrowable {
        if(i == 10) throw new TestThrowable();
        i++;
        rec();
    }
}

问题是,是否有更好的方法来达到同样的目的?另外,以这种方式做事有什么不妥之处吗?

解决方法

实际上,在“正常”程序员不会想到使用它们的某些情况下使用异常是一个很好的主意.例如,在启动“规则”并发现它不起作用的解析器中,异常是回退到正确恢复点的一种非常好的方法. (这与您提出的突破递归的程度类似.)

有一个经典的反对意见是“例外并不比一个goto更好”,这显然是错误的.在Java和大多数其他合理的现代语言中,您可以拥有嵌套的异常处理程序和最终的处理程序,因此当通过异常传输控件时,精心设计的程序可以执行清理等.事实上,这样的异常在几个方面更可取返回代码,因为使用返回代码,您必须在每个返回点添加逻辑以测试返回代码,并在退出例程之前查找并执行正确的finally逻辑(可能是几个嵌套的部分).使用异常处理程序,通过嵌套异常处理程序可以相当自动化.

例外确实带来了一些“包袱” – 例如Java中的堆栈跟踪.但Java异常实际上非常有效(至少与其他语言中的实现相比),因此如果不过度使用异常,性能应该不是一个大问题.

[我将补充一点,我有40年的编程经验,自70年代末以来我一直在使用异常.独立“发明”try / catch / finally(称为BEGIN / ABEXIT / EXIT)1980年.]

一个“非法”的题外话:

我认为在这些讨论中经常遗漏的事情是计算中的第一个问题不是成本或复杂性或标准或性能,而是控制.

通过“控制”,我不是指“控制流”或“控制语言”或“运算符控制”或经常使用术语“控制”的任何其他上下文.我的意思是“控制复杂性”,但它不仅仅是 – 它是“概念控制”.

我们都做到了(至少我们这些已经编程超过6周的人) – 开始编写一个没有真正结构或标准的“简单小程序”(除了我们可能习惯使用的那些),不要担心它的复杂性,因为它“简单”和“一次性”.但是,在10个案例或100个案例中,根据具体情况,“简单的小程序”可能会变成怪物.

我们放松了对它的“概念控制”.修复一个bug会引入另外两个bug.程序的控制和数据流变得不透明.它的表现方式我们无法理解.

然而,按照大多数标准,这个“简单的小程序”并不复杂.它并不是那么多行代码.很可能(因为我们是熟练的程序员),它被分解为“适当”数量的子程序.通过复杂性测量算法运行它并且可能(因为它仍然相对较小并且“子程序化”)它将得分并不特别复杂.

最终,维护概念控制是几乎所有软件工具和语言背后的驱动力.是的,像汇编程序和编译器这样的东西使我们更有效率,生产力是所宣称的驱动力,但是提高生产力的大部分原因是因为我们不必忙于“不相关”的细节,而是可以专注于我们想要的概念实施.

概念控制的重大进步发生在计算历史的早期,因为“外部子程序”的出现变得越来越独立于它们的环境,允许“关注点分离”,子程序开发人员不需要了解子程序的环境,并且子程序的用户不需要了解子程序内部.

BEGIN / END和“{…}”的简单开发产生了类似的进步,因为即使是“内联”代码也可以从“在那里”和“在这里”之间的某些隔离中受益.

我们认为理所当然的许多工具和语言功能都很有用,因为它们有助于保持对更复杂的软件结构的智能控制.人们可以通过它如何帮助实现这种智能控制,非常准确地衡量新工具或功能的效用.

其中一个问题是剩下的最大困难是资源管理.这里的“资源”是指任何实体 – 对象,打开文件,分配堆等 – 可能在程序执行过程中“创建”或“分配”,随后需要某种形式的释放. “自动堆栈”的发明是这里的第一步 – 变量可以“堆叠”分配,然后当“分配”它们的子程序退出时自动删除. (这是一个非常有争议的概念,许多“当局”建议不要使用该功能,因为它会影响性能.)

但是在大多数(全部?)语言中,这个问题仍然以某种形式存在.使用显式堆的语言需要“删除”任何“新”,例如.必须以某种方式关闭打开的文件.锁必须被释放.其中一些问题可以是精细的(使用GC堆,例如)或纸糊(引用计数或“父母”),但是没有办法消除或隐藏所有这些问题.而且,虽然在简单的情况下管理这个问题是相当简单的(例如,新的对象,调用使用它的子程序,然后删除它),现实生活很少那么简单.有一种方法可以进行十几个不同的调用,在调用之间有点随机分配资源,这些资源具有不同的“生命周期”,这种情况并不少见.并且一些调用可能返回改变控制流的结果,在某些情况下导致子例程退出,或者它们可能导致子例程体的某个子集周围的循环.知道如何在这种情况下释放资源(释放所有正确的资源而不是错误的资源)是一项挑战,随着子程序随着时间的推移而变得更加复杂(因为所有复杂的代码都是如此).

try / finally机制的基本概念(暂时忽略了catch方面)很好地解决了上述问题(尽管远非完美,但我承认).对于需要管理的每个新资源或资源组,程序员引入try / finally块,将释放逻辑放在finally子句中.除了确保资源将被释放的实际方面之外,这种方法的优点是可以清楚地描述所涉及资源的“范围”,提供一种“有力维护”的文档.

这种机制与catch机制相结合的事实有点意外,因为在正常情况下用于管理资源的相同机制用于在“异常”情况下管理它们.由于“异常”(表面上)是罕见的,因此最小化该稀有路径中的逻辑量总是明智的,因为它永远不会像主线那样经过良好测试,并且因为“概念化”错误情况对于平均值来说特别困难程序员.

当然,尝试/最后有一些问题.其中第一个是块可以嵌套得如此深,以至于程序结构变得模糊而不是澄清.但这是与do循环和if语句相同的问题,它等待语言设计者的一些启发性见解.更大的问题是,尝试/最终有抓住(甚至更糟的是,例外)行李,这意味着它不可避免地被降级为二等公民. (例如,除了现在已弃用的JSB / RET机制之外,最终甚至不存在Java字节码中的概念.)

还有其他方法. IBM iSeries(或“System i”或“IBM i”或他们现在称之为的任何内容)具有将清理处理程序附加到调用堆栈中的给定调用级别的概念,以便在关联程序返回(或异常退出)时执行).虽然这在当前形式下是笨拙的,并不真正适合Java程序中所需的精细控制级别,例如,它确实指向了潜在的方向.

当然,在C语言系列(但不是Java)中,能够将代表资源的类实例化为自动变量,并使对象析构函数在退出变量范围时提供“清理”. (注意,这个方案,在本质上,主要使用try / finally.)这在很多方面都是一种很好的方法,但它需要一套通用的“清理”类或者为每种不同类型定义一个新类.资源,创造一个文本庞大但相对无意义的类定义的潜在“云”. (而且,正如我所说,它不是Java目前形式的选择.)

但我离题了.

java – 对异常以外的事物使用Throwable的更多相关文章

  1. ios – 嵌套递归函数

    我试图做一个嵌套递归函数,但是当我编译时,编译器崩溃.这是我的代码:编译器记录arehere解决方法有趣的…它似乎也许在尝试在定义之前捕获到内部的引用时,它是bailing?以下修复它为我们:当然没有嵌套,我们根本没有任何问题,例如以下工作完全如预期:我会说:报告!

  2. swift override --有一个递归问题未解决

    classca{varcount:Int{get{return1;}set{self.count=newValue;}}funcdescribe()->String{return"ca";}}classcb:ca{overridefuncdescribe()->String{return"cb";}overridevarcount:Int{get{return2;}set{//引起了递归调用,未找

  3. Swift2.0语言教程之函数嵌套调用形式

    Swift2.0语言教程之函数嵌套调用形式Swift2.0语言函数嵌套调用形式在Swift中,在函数中还可以调用函数,从而形成嵌套调用。以下将对这两种调用进行详细讲解。调用方式如图7.4所示。图7.4函数嵌套的形式以下将使用函数的嵌套调用实现对s=22!这个数值,即调用f1()函数,计算22,结果为4,然后在调用f2()函数,对4的阶乘求取,计算完成22!但是在Swift语言中递归必须要有一个满足结束的条件。

  4. 【Swift】学习笔记(九)——枚举

    因为类完全可以替代枚举。不过swift中也有许多类的特性被枚举支持。这样判断必须穷举所有成员,否则就需要增加default这个选项了。使用递归枚举时,编译器会插入一个中间层。

  5. Swift实现的快速排序及sorted方法的对比

    Swift语言有着优秀的函数式编程能力,面试的时候面试官都喜欢问我们快速排序,那么用Swift如何实现一个快速排序呢?然后实现快速排序的方法:可以发现使用Swift实现快速排序的代码非常的简洁。在看完这段代码后我做了如下思考:既然是排序,那么必然可以使用系统的sorted方法,效果如何呢?对于快排最头疼的顺序性数组,sorted的重复次数只有n次!说明在面对这种类型的数组的时候sorted方法进行过判断,直接输出了。

  6. 《swift2.0 官方教程中文版》 第2章-08枚举

    importFoundation//在Swift中,枚举类型是一等公民。像Swift中其他类型一样,它们的名字必须以一个大写字母开头。给枚举类型起一个单数名字而不是复数名字,以便于读起来更加容易理解:vardirectionToHead=Compasspoint.West//directionToHead的类型可以在它被Compasspoint的一个可能值初始化时推断出来。//使用枚举成员的rawValue属性可以访问该枚举成员的原始值:letearthsOrder=Planet2.Earth.rawVa

  7. swift枚举

    Swift中的枚举更加灵活,不必给每一个枚举成员提供一个值。它是Directionoperation类型,因为swift中的枚举不会自动给成员赋值为0,1…枚举类型易扩展。原始值的隐式赋值在使用原始值为整数或者字符串类型的枚举时,不需要显式地为每一个枚举成员设置原始值,Swift将会自动为你赋值。

  8. Swift学习之路04-枚举

    枚举在Swift中,枚举类型是一等类型。*注意与C和Objective-C不同,Swift的枚举成员在被创建时不会被赋予一个默认的整型值。在上面的nt例子中,north,East和West不会被隐式地赋值为0,1,2和3。相反,这些枚举成员本身就是完备的值,这些值的类型是已经明确定义好的Compasspoint类型。下面的例子是Compasspoint枚举的细化,使用字符串类型的原始值来表示各个方向的名称:上面例子中,Compasspoint.south拥有隐式原始值South,依次类推。使用递归枚举时,

  9. The Swift Programming Language学习笔记九——枚举

    Swift中的枚举更加灵活,不必给每一个枚举成员提供一个值。在Swift中,枚举类型是一等类型。注意,与C和Objective-C不同,Swift的枚举成员在被创建时不会被赋予一个默认的整型值。使用let和var定义枚举常量和变量。使用switch语句匹配枚举值使用switch语句匹配单个枚举值。强制穷举确保了枚举成员不会被意外遗漏。枚举的这种特性跟其他语言中的可识别联合,标签联合,或者变体相似。使用枚举成员的rawValue属性可以访问该枚举成员的原始值。

  10. Swift讲解专题九——枚举

    Swift讲解专题九——枚举一、引言在Objective-C语言中,没有实际上是整型数据,Swift中的枚举则更加灵活,开发者可以不为其分配值类型把枚举作为独立的类型来使用,也可以为其分配值,可以是字符,字符串,整型或者浮点型数据。

随机推荐

  1. 基于EJB技术的商务预订系统的开发

    用EJB结构开发的应用程序是可伸缩的、事务型的、多用户安全的。总的来说,EJB是一个组件事务监控的标准服务器端的组件模型。基于EJB技术的系统结构模型EJB结构是一个服务端组件结构,是一个层次性结构,其结构模型如图1所示。图2:商务预订系统的构架EntityBean是为了现实世界的对象建造的模型,这些对象通常是数据库的一些持久记录。

  2. Java利用POI实现导入导出Excel表格

    这篇文章主要为大家详细介绍了Java利用POI实现导入导出Excel表格,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  3. Mybatis分页插件PageHelper手写实现示例

    这篇文章主要为大家介绍了Mybatis分页插件PageHelper手写实现示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  4. (jsp/html)网页上嵌入播放器(常用播放器代码整理)

    网页上嵌入播放器,只要在HTML上添加以上代码就OK了,下面整理了一些常用的播放器代码,总有一款适合你,感兴趣的朋友可以参考下哈,希望对你有所帮助

  5. Java 阻塞队列BlockingQueue详解

    本文详细介绍了BlockingQueue家庭中的所有成员,包括他们各自的功能以及常见使用场景,通过实例代码介绍了Java 阻塞队列BlockingQueue的相关知识,需要的朋友可以参考下

  6. Java异常Exception详细讲解

    异常就是不正常,比如当我们身体出现了异常我们会根据身体情况选择喝开水、吃药、看病、等 异常处理方法。 java异常处理机制是我们java语言使用异常处理机制为程序提供了错误处理的能力,程序出现的错误,程序可以安全的退出,以保证程序正常的运行等

  7. Java Bean 作用域及它的几种类型介绍

    这篇文章主要介绍了Java Bean作用域及它的几种类型介绍,Spring框架作为一个管理Bean的IoC容器,那么Bean自然是Spring中的重要资源了,那Bean的作用域又是什么,接下来我们一起进入文章详细学习吧

  8. 面试突击之跨域问题的解决方案详解

    跨域问题本质是浏览器的一种保护机制,它的初衷是为了保证用户的安全,防止恶意网站窃取数据。那怎么解决这个问题呢?接下来我们一起来看

  9. Mybatis-Plus接口BaseMapper与Services使用详解

    这篇文章主要为大家介绍了Mybatis-Plus接口BaseMapper与Services使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  10. mybatis-plus雪花算法增强idworker的实现

    今天聊聊在mybatis-plus中引入分布式ID生成框架idworker,进一步增强实现生成分布式唯一ID,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

返回
顶部