java - 是否有收集异常的标准方法?

2022-09-02 04:44:27

我有一个Java程序,可以解析几个不同的输入文件。即使在此输入文件中发现错误,解析仍然可以继续并收集其他几个错误。因此,我想做的不是抛出和异常并停止解析过程,而是将异常注册到某个地方,然后继续解析并以类似的方式收集其他几个错误,然后最后我想检查是否报告了任何错误,并根据此失败或继续。

当然,我总是可以通过编写 ExceptionRegister 或任何类来手动执行此操作,但我想知道两件事:

1)这种方法有问题吗?你知道我想做什么的替代设计吗?

2)有没有一种标准的方法可以做到这一点?(例如,如果可能的话,我想使用内置功能,而不是滚动我自己的类)

谢谢

编辑:我不知道为什么,但有人在我接受他的答案之前删除了他的答案。无论如何,我认为简单的数据结构应该有效。基本上,我将编写一个收集多个错误消息的异常类。然后,我将调用它的 throw 方法,如果它至少注册了一条错误消息,则会引发自身。

编辑2:这里有更多的澄清。我的问题与解析无关。解析只是一个例子,因为我的程序做了一些解析。这样想:我正在运行一个算法,如果出现错误,我可以继续该算法来收集更多错误,这样我就可以不打印一个错误,并且在修复后打印第二个错误,我可以将这两个错误打印在一起。


答案 1

当您无法再处理输入时,确实应该使用异常。它们是特殊情况,您的代码说“我放弃了,我缺少一些信息,或者我不是为此而生的”。关于如何定义这种情况,这是一个灰色地带,但比尔·维纳斯(Bill Venners)在这篇(旧!)文章中提出的通常的哲学是:

避免使用异常来指示可以合理预期为方法典型功能一部分的条件。

在你的情况下,听起来你必须解析的内容可能不正确,但这是你的程序所期望的,并且不会破坏足够的契约来停止解析。另一方面,例如,如果输入语法中的错误导致解释的其余部分失败,则可以使用可接受的异常。

但是人们仍然使用异常,因为它们非常方便停止执行和向上堆栈,而无需进入通过结果返回的繁琐细节。但是对于它的对应物,它们可能会产生棘手的结果,因为您在某些对象中留下了一些无人值守的状态。

您的要求听起来更像是需要验证模式,而不是一个可能导致处理停止的异常。一个停止所有处理的异常:如果抛出一个,其余的将被忽略。但你建议你收集它们,而不是扔掉它们。所以我想说,在这种情况下,为什么要使用异常呢?似乎您确实希望返回正确的结果,而不是停止程序的执行。

因为如果你仍然沿着这条路走下去,你可能会在最后抛出一组异常。你扔哪一个?在您创建的异常收集器中,哪一个优先?

以Eclipse为例,它有这个巨大的平台来处理大量的集合插件贡献。它们使用适当的通信通道在问题窗格中或通过执行后台任务来记录任何警告和错误。后者的执行通常会返回IStatus对象或变体。基于此对象,接收状态的代码决定对它执行操作。IStatus

因此,就我个人而言,我会开发一个类似的对象,它将收集所有必要的用户错误(而不是程序的错误),它不会破坏程序的执行和合同的可接受部分。此对象可以包含错误的严重性,其来源,有关如何修复它的提示(这可以是一个字符串,甚至是包含用于显示错误的精确逻辑或可能是部分自动修复的方法)等...执行完成后,解析的结果将获取这些状态对象并对其执行操作。如果存在错误,请通过 UI 通知用户并记录下来。

因此,它基本上与您最初建议的方法相同,减去异常,并减去跳过堆栈的商品,这可能导致令人讨厌的副作用和非常难以调试的错误。


答案 2

我想我现在明白了。您实际尝试做的是收集解析错误(您表示为异常)并继续解析当前输入文件。

没有标准的方法来执行此操作:

“异常寄存器”实际上只不过是解析错误描述符的列表...大概是一些解析器异常。如果可以在适当的位置捕获异常,则将其添加到“寄存器”中是微不足道的。

困难的部分是你没有谈论的功能:

  • 如何捕获错误的位置

  • 如何让解析器在遇到解析器错误时继续解析。

这些解决方案取决于您如何实现解析器。

  • 如果您使用的是解析器生成器,则 PGS 文档很有可能说明如何实现这一点。

  • 如果要手动实现解析器,则需要滚动自己的代码来跟踪错误位置并进行语法错误恢复。


基本上,我将编写一个收集多个错误消息的异常类。然后,我将调用它的 throw 方法,如果它至少注册了一条错误消息,则会引发自身。

这听起来像是对例外的滥用。一个更好的主意是在列表中累积错误,然后在列表不为空时创建/引发异常。如果要避免重复代码,请在帮助器类中使用静态方法。

有条件地抛出自己的异常是(IMO)奇怪的!而且,创建许多不太可能引发的异常可能是低效的。(根据 JVM 的不同,异常的代价高昂的部分通常是创建异常并捕获堆栈帧。费用可能很大。


推荐