【问题标题】:java - is there a standard way of collecting exceptions?java - 有没有收集异常的标准方法?
【发布时间】:2013-11-09 01:28:26
【问题描述】:

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

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

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

2) 有标准的方法吗? (例如,如果可能,我想使用内置功能,而不是滚动我自己的类)

谢谢

编辑:我不知道为什么,但在我接受他的答案之前,有人刚刚删除了他的答案。无论如何,我认为简单的数据结构应该可以工作。基本上,我将编写一个异常类来收集多个错误消息。然后我将它称为 throw 方法,如果它至少注册了一条错误消息,就会抛出自己。

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

【问题讨论】:

  • 重新编辑:为什么在这种情况下需要扩展 Exception
  • 我删除了它,因为您告诉我问题不在于解析输入文件中的异常堆栈跟踪。我根据您(显然)真正提出的问题创建了一个新答案。
  • 不是专门的 Java 答案,但您可能正在寻找的类型是应用函子。 Scalaz 库提供了一个名为 Validation 的库。

标签: java exception exception-handling


【解决方案1】:

当您无法再处理输入时,应该真正使用异常。它们是您的代码说“我放弃,我遗漏了一些信息或者我不适合这个”的特殊情况。这是一个关于如何定义此类案例的灰色地带,但正如 Bill Venners 在this (old!) article 中所说的那样,通常的理念是:

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

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

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

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

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

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

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

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

【讨论】:

    【解决方案2】:

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

    没有标准的方法来做到这一点:

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

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

    • 如何捕获错误的位置

    • 当解析器出错时如何让解析器继续解析。

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

    • 如果您使用解析器生成器,PGS 文档很有可能会解释如何实现它。

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


    基本上,我将编写一个收集多个错误消息的异常类。然后我将它称为 throw 方法,如果它至少注册了一条错误消息,就会抛出自己。

    这听起来像是滥用异常。一个更好的办法是将错误累积在一个列表中,如果列表非空,然后创建/抛出异常。如果您想避免重复代码,请在帮助程序类中使用静态方法。

    有条件地抛出自己的异常是(IMO)奇怪的!并且创建许多您不太可能抛出的异常可能是低效的。 (取决于 JVM,异常的代价高昂的部分通常是创建异常并捕获堆栈帧。开销可能很大。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-28
      • 1970-01-01
      • 2023-03-13
      • 2015-03-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多