在抛出旧异常时抛出新异常

时间:2010-04-26 20:48:30

标签: java c++ exception-handling

如果析构函数在异常导致的堆栈展开期间抛出C ++,程序将终止。 (这就是析构函数永远不应该使用C ++的原因。)例如:

struct Foo
{
    ~Foo()
    {
        throw 2;   // whoops, already throwing 1 at this point, let's terminate!
    }
};

int main()
{
    Foo foo;
    throw 1;
}

terminate called after throwing an instance of 'int'

This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.

如果由于相应try块中的异常而在Java中输入finally块,并且finally块抛出第二个异常,则会以静默方式吞下第一个异​​常。例如:

public static void foo() throws Exception
{
    try
    {
        throw new Exception("first");
    }
    finally
    {
        throw new Exception("second");
    }
}

public static void main(String[] args)
{
    try
    {
        foo();
    }
    catch (Exception e)
    {
        System.out.println(e.getMessage());   // prints "second"
    }
}

这个问题在我脑海中浮现:编程语言是否可以同时处理多个异常?这会有用吗?你有没有错过这种能力?有没有一种语言可以支持这个?有这种方法的经验吗?

有什么想法吗?

8 个答案:

答案 0 :(得分:5)

考虑流量控制。无论如何,例外基本上只是花哨setjmp / longjmpsetcc / callcc。异常对象用于选择要跳转到的特定位置,如地址。异常处理程序只是简单地处理当前异常longjmp,直到它被处理完毕。

一次处理两个异常只是将它们捆绑在一起,这样结果就可以产生一致的流量控制。我可以想到两个选择:

  • 将它们组合成一个无法捕获的异常。这相当于展开整个堆栈并忽略所有处理程序。这会产生异常级联导致完全随机行为的风险。
  • 以某种方式构建他们的笛卡尔积。是的,没错。

C ++方法很好地满足了可预测性的需要。

答案 1 :(得分:3)

您可以链接例外。 http://java.sun.com/docs/books/tutorial/essential/exceptions/chained.html

try {

} catch (IOException e) {
    throw new SampleException("Other IOException", e);
}

你也可以试试你的内心。

try{
}catch(Exception e){
}finally{
    try{
      throw new SampleException("foo");
    }catch(Exception e){
    }
}

编辑:

你也可以有多次捕获。 我不认为多个异常是个好主意,因为异常已经是你需要恢复的东西了。我能想到的有多个异常的唯一原因是,如果你将它用作逻辑的一部分(比如多次返回),那将偏离异常概念的最初目的。 此外,你怎么能同时产生两个例外?

答案 2 :(得分:2)

编程语言可以处理多个异常吗?当然,我不明白为什么不。这有用吗?不,我会说不会。错误处理和恢复是非常困难的 - 我没有看到如何在问题上添加组合爆炸会有所帮助。

答案 3 :(得分:0)

是的,一种语言可以支持一次抛出多个例外;然而,这也意味着程序员也需要同时处理多个异常,因此肯定存在权衡。我听说过有这种语言,虽然我无法提出我的头脑清单;我相信LINQ或PLINQ可能是这些语言之一,但我不太记得。无论如何,有多种方法可以抛出多个异常......一种方法是使用异常链接,通过强制一个异常成为另一个异常的“cause”或“previousProgatingException”,或者将所有异常置换为表示已抛出多个异常这一事实的单个异常。我想一种语言也可以引入一个catch子句,允许你一次指定多个异常类型,虽然这将是一个糟糕的设计选择,恕我直言,因为处理程序的数量足够大,这将导致爆炸catch子句只是为了处理每一种可能的组合。

答案 4 :(得分:0)

C ++ std :: exception_ptr允许您存储异常。因此,应该可以将异常嵌入到其他异常中,并给您一个关于抛出异常的堆栈的印象。如果您想知道实际异常的根本原因,这可能很有用。

答案 5 :(得分:0)

并发多个抛出异常可能有用的一种情况是使用JUnit进行单元测试:

  • 如果测试失败,则抛出异常(由测试中的代码或断言产生)。
  • 测试后调用每个@After方法,无论测试失败还是成功。
  • 如果After方法失败,则抛出另一个异常。
  • 在我的IDE(Eclipse)中只显示After方法中抛出的异常以获取测试结果。

我知道JUnit会向其测试监听器通知两个异常,并且在Eclipse中调试测试时,我可以看到JUnit视图中出现的第一个异常,只是在不久之后被第二个异常替换。

这个问题应该可以通过让Eclipse记住给定测试的所有通知来解决,而不仅仅是最后一个。拥有“并行异常”,finally中的异常不会吞掉try中的异常,也会解决此问题。

答案 6 :(得分:0)

答案 7 :(得分:0)

在托管平台中,我可以想到让处理器将异常“提升”到某个更强大但对应用程序并不完全致命的事情可能有用的情况。例如,“命令”对象的处理程序可能会尝试展开其关联连接的状态以取消任何部分执行的命令。如果可行,底层代码可能会尝试使用连接执行其他操作。如果尝试“取消”不起作用,则异常应该传播到连接将被销毁的级别。在这种情况下,异常包含一个“内部异常”可能是有用的,尽管我知道实现这一目的的唯一方法是尝试在catch块中展开而不是“finally”块。