我有一个解析几个不同输入文件的Java程序。即使在此输入文件中发现错误,解析仍可继续并收集其他几个错误。所以我想做的不是抛出异常并停止解析过程,我想将异常注册到某个地方,然后继续解析并以类似的方式收集其他几个错误,最后我想检查是否报告任何错误,并根据此情况失败或继续。
当然,我总是可以通过编写ExceptionRegister或任何类来手动执行此操作,但我想知道两件事:
1)这种方法有问题吗?你知道我想做什么的替代设计吗?
2)有没有一种标准的方法呢? (例如,如果可能的话,我不想滚动我自己的类,而是想使用内置功能)
由于
编辑:我不知道为什么但是在我接受他的回答之前,有人刚刚删除了他的回答。无论如何,我认为简单的数据结构应该有效。基本上,我将编写一个收集多个错误消息的异常类。然后我将调用它的throw方法,如果它至少注册了一条错误消息,则抛出该方法。EDIT2:这里有更多说明。我的问题与解析无关。解析只是一个例子,因为我的程序做了一些解析。想一想:我正在运行一个算法,如果出现错误,我可以继续算法收集更多的错误,这样就不会打印出一个错误,当它被修复时,打印出第二个错误,我可以将这两个错误一起打印出来。 / p>
答案 0 :(得分:5)
当您无法再处理输入时,应该真正使用异常。它们是特殊情况,你的代码说“我放弃了,我错过了一些信息,或者我不是为了这个”。这是如何定义此类案例的灰色区域,但Bill Venners在this (old!) article中提出的通常理念是:
避免使用例外来表明合理的条件 预期作为该方法典型功能的一部分。
在您的情况下,听起来您需要解析的内容可能不正确,但这是您的程序所期望的,并且不会破坏合同以停止解析。另一方面,例如,如果输入语法中的错误导致其余解释失败,则可以使用可接受的异常。
但是人们仍然使用异常,因为它们非常方便停止执行并上升到堆栈而不需要处理流过结果返回的繁琐细节。但是在它的对应物上,当你在一些物体中留下一些无人看管的状态时,它们会产生棘手的结果。
您的要求听起来更像是一个验证模式,而不是一个可能导致处理停止的异常。停止所有处理的一个例外:如果你抛出一个,其余的将被忽略。但是你建议你收集它们而不是扔掉它们。所以我会说,在那种情况下,为什么要使用例外呢?看来你确实希望返回正确的结果而不是停止程序的执行。
因为如果你仍沿着这条路走下去,你可以在最后抛出一系列异常。你扔哪一个?在您创建的Exception收集器中哪一个优先?
以Eclipse为例,它拥有这个巨大的平台来处理大量的集合插件贡献。他们使用适当的通信渠道记录问题窗格或through the execution of background task中的任何警告和错误。后者的执行通常会返回IStatus object或变体。基于此IStatus
对象,接收状态的代码决定对其进行操作。
因此,就个人而言,我会开发一个类似的对象来收集所有必要的用户错误(而不是程序的错误),这不会破坏程序的执行和合同的可接受部分。此对象可以包含错误的严重性,其来源,如何修复它的提示(这可以是字符串,甚至是包含用于显示错误或可能是部分自动修复的精确定位逻辑的方法)等。 ..一旦执行完毕,解析的结果将获得这些状态对象并对其进行操作。如果有错误,请通过用户界面通知用户并将其记录下来。
所以它与你最初建议的方法基本相同,减去异常并减去跳过堆栈的商品,这可能导致令人讨厌的副作用,并且很难调试错误。
答案 1 :(得分:2)
我想我现在明白了。您实际上要做的是收集解析错误(您表示为异常)并继续解析当前输入文件。
没有标准的方法可以做到这一点:
“异常寄存器”实际上只是一个解析错误描述符列表......可能是一些解析器异常。如果你可以在适当的时候捕获异常,那么将它添加到“寄存器”是很容易的。
困难的部分是你不谈论的功能:
如何捕获错误的位置
如何在解析器出错时让解析器继续解析。
这些解决方案取决于您如何实现解析器。
如果您使用的是解析器生成器,PGS文档很可能会解释如何实现它。
如果您手动实现解析器,则需要使用自己的代码来跟踪错误位置并进行语法错误恢复。
基本上,我会写一个收集几条错误消息的异常类。然后我将调用它的throw方法,如果它至少注册了一条错误消息,则抛出该方法。
这听起来像是滥用例外。更好的想法是在列表中累积错误,然后然后创建/抛出异常(如果列表非空)。如果要避免重复代码,请在辅助类中使用静态方法。
有条件抛出的异常是(IMO)奇怪的!并且创建许多您不太可能抛出的异常可能效率低下。 (根据JVM,异常的昂贵部分通常是创建异常并捕获堆栈帧。费用可能很大。)