异常规范,是否有用?

时间:2012-06-28 11:50:14

标签: java c++ exception exception-safety exception-specification

首先免责声明:这不是导致语言战#34;我的报告真的需要这个(关于这个主题的说明),我只想提出有效而坚实的论据 好的,这就是问题:
在C ++中,异常规范已从C ++ 11标准中删除,因为它被认为造成了更多的伤害而不是好处 另一方面,在Java中,异常规范被认为是一种好的和有用的东西 这两个概念(具有例外规范的目的)是否在这两种语言中有所不同,这就是为什么这两个社区对这些概念的看法不同或那些概念是相似/相同的? 哪一个?异常规范是好事还是坏事?或者它在Java中很好,因为(在这里我想看到一些原因)并且在C ++中很糟糕,因为(原因在这里)。
感谢任何有建设性帮助的人。

4 个答案:

答案 0 :(得分:7)

除了其他任何内容之外,我认为Java和C ++异常规范之间的主要区别在于,在Java中,规范是函数类型的一部分,并且编译器强制您不能允许已检查的异常来转义函数,除非它们'是你职能类型的一部分。

因此,Java检查异常提供了一种有限/有缺陷的方法来跟踪哪些函数抛出异常。 C ++异常规范提供了一种有限/有缺陷的方法来防止对函数的调用抛出特定异常(或任何异常)。

由于它们有不同的目的,因此必须分别评估它们的成功或失败。在某种程度上,实际的程序员避免使用它们,我认为你可以放心地说它们都有些失败,但这就是你可以用两种方式评估相同的方式。对于Java来说,这个程度相当高,而对于C ++来说则非常高。他们所拥有的有益用途,以及每种语言的确切成功程度,都是不同的。

答案 1 :(得分:1)

Java和C ++中的异常规范以非常不同的方式工作。

这是C ++观点的非常好的信息来源。 http://www.gotw.ca/publications/mill22.htm

C ++设计的主要缺点是,如果你抛出一个意外的异常,你的程序很可能会崩溃(详见链接)。因此,异常规范是一个约束,它将适用太晚。

Herb Sutter关闭文章说:

Moral #1: Never write an exception specification.

Moral #2: Except possibly an empty one, but if I were you I’d avoid even that.

Java异常规范框架不同,您有两种类型的异常:checked(编译时)和运行时异常(非常类似于没有异常规范的C ++)。

使用已检查的异常,编译器将强制开发人员处理这些异常,否则应用程序将无法编译。这是好的和有用的,但运行时和已检查异常之间的区别并不完全清楚,并且取决于开发人员,它可能会产生混淆。即使使用简单的程序习惯用法(例如Checked exception specification and strategy pattern),检查的异常也会涉及困难的决定。

最后的结果,像往常一样,没有明确的语言功能,是一个很糟糕的使用它。例如,C#设计师决定放弃它们。

我认为,java设计比这个特定主题的C ++ 03更好(而且我是C ++的忠实粉丝),因为它允许开发人员以更具描述性的方式编写更好的代码。但是,您需要花费精力(编码标准和代码审查)在开发团队中生成一致的代码。

答案 2 :(得分:0)

几年前,Java的检查异常已经失宠,因为正如你所说的那样,它们造成的伤害大于帮助。现在人们主要通过包裹RuntimeException来设计如何避免它们的方法。

在Effective Java中,Josh Bloch仍然在“特殊但预期的结果”的情况下为被检查的例外辩护,但事实是,API编写者不是决定哪个结果是预期的,哪个不是。例如,即使是FileNotFoundException,在上下文中也可能是意外的,致命的结果。

所以,至少,没有公共图书馆应该使用已检查的例外。

答案 3 :(得分:-1)

C ++和Java在异常规范方面甚至没有远程可比性,因为它们在例外方面有所不同:

  • C ++仅在需要时使用动态分配,程序员尽可能使用堆栈分配(如果只是为了避免释放内存的问题)
  • Java几乎一直使用动态分配;对于用户定义类型的对象,对于数组(甚至是编译时已知大小的数组)

在C ++中,许多函数可以保证不会抛出任何异常。我不是在谈论异常规范,而是关于函数的记录和实际行为。对于简单函数调用的情况,只要没有可以抛出异常的语句,那么异常规范是什么并不重要。

[对于从不抛出异常的函数,异常规范在需要测量抛出函数异常的可能性的调用代码时起作用,以便以一种将对象保留为对象的方式调用非抛出函数如果中间有异常,则为坏状态。这是在现代C ++中用noexcept完成的,在旧的C ++中,这可能是用更加冗长的方式(也就是库之间不兼容)和类型特征完成的。]

[注意编译器总是有权查看在编译期间可见的函数体,以确定它是否可以抛出异常,并相应地优化调用代码(如果至少减少异常表的大小)。抛出规范只会在编译器无法看到代码无法抛出时帮助编译。]

在C ++中,这" 永远不会抛出"需求可以记录,并由编译器强制执行,使用空抛出规范(旧的throw()或现代的nothrow)。

Java 没有等效的非常有用的保证。它可以声明某些函数不会抛出一些异常,这对于编写异常安全代码是无用的。