Java 为什么必须在类定义中编写抛出异常?

Java 为什么必须在类定义中编写抛出异常?,java,exception,Java,Exception,来自C#, 我只是不理解在类/方法定义之后编写的“抛出异常”: public void Test() throws Exception 你一定要写这个吗? 如果你没有呢? 如果我调用一个有这个符号的方法,我必须捕获它吗?在所有情况下,你都不必写它,只要你的方法抛出一个选中的异常(一个异常是异常的子类,而不是运行时异常的子类)。这是因为您的方法签名是一个契约,它向所有调用它的代码声明它有可能抛出给定的异常。因为它是一个检查过的异常——一个可以预期的异常——调用代码需要预测看到抛出异常的可能性,并

来自C#, 我只是不理解在类/方法定义之后编写的“抛出异常”:

public void Test() throws Exception
你一定要写这个吗? 如果你没有呢?
如果我调用一个有这个符号的方法,我必须捕获它吗?

在所有情况下,你都不必写它,只要你的方法抛出一个选中的
异常(一个异常是
异常的子类,而不是
运行时异常的子类)。这是因为您的方法签名是一个契约,它向所有调用它的代码声明它有可能抛出给定的异常。因为它是一个检查过的异常——一个可以预期的异常——调用代码需要预测看到抛出异常的可能性,并且需要能够处理它

要回答您的两个具体问题:

  • 你必须写它吗/如果不写怎么办:如果你的方法抛出一个选中的异常,那么是的,你必须在方法签名中声明它。如果不这样做,那么代码将无法编译
  • 你必须抓住它吗:你必须用它做点什么。调用该方法的代码可以捕获并处理该方法,也可以捕获并重新抛出该方法,或者只是将其传递到链上。为了向上传递它,调用该方法的代码必须自己声明它抛出相同的异常——例如,如果方法
    bar
    可以抛出
    SomeException
    ,而方法
    foo
    调用
    bar
    ,并且不想捕获异常,
    foo
    的方法签名将声明它也抛出
    SomeException

非常善于详细解释这一点,我一直认为这是一个很好的参考,可以传递给大家。

如果抛出的异常是检查异常,则必须编写它,这意味着调用方有明确的责任捕获或重新抛出异常。

如果在代码中捕获异常,则不必抛出异常。如果您没有捕捉到它,它会传递给调用者,这就是为什么您需要throws子句。

要回答您的特定问题,您几乎不想说
抛出异常本身

throws
子句通知此方法的用户,他们必须处理一个异常情况。例如,您可能有一个
IOException
,这是由于使用了一些文件操作方法(例如,无法打开有问题的文件)而导致的。如果您没有在本地处理该异常,则需要声明您的方法
将该异常抛出给调用方


现代IDE将通知您,对于已检查的异常,您需要在使用方法时处理它们,或者(通过throws子句)将它们从调用树的方法中抛出。

基本上是的,如果不这样做,您的程序将无法编译。这称为检查异常(任何异常都是检查异常,除非它是或扩展了RuntimeException或Error)

如果抛出异常的方法中有任何东西,除非您捕获或异常,否则将无法编译,然后调用该方法的任何东西都必须以相同的方式处理异常。C++中的

< P>(我不能C,但它可能类似)关键字
throw
是对所有异常类型的限制,因此如果没有关于抛出异常的规范,您可以假设它可以是任何类型


在Java中,您可以假设如果没有使用关键字
throws
,那么这个方法不会抛出任何人。(您可以确定,但不必存在运行时异常)。因此,如果有一些关于抛出的规范,您必须抓住它,将其向上传播。

在.net中不存在检查与未检查异常的概念。 最初的Java专家的建议是,如果必须声明抛出的已检查异常,那么调用方将知道他/她必须捕获它们。例如,如果您正在处理IO库,if将强制您捕获IOException

try {
    file.delete();
} catch (IOException x) {
    // do something
}
不幸的是,Java中过度使用了检查异常(参见spring)。对于检查异常的滥用以及它们如何污染代码,有很多批评。经常抛出已检查异常的库会导致用户编写如下代码:

try {
    file.delete();
} catch (IOException e) {
   throw new RuntimeException(e);
}

如果您正在编写一个库,请考虑您检查的异常是否会妨碍/打扰用户,以及他/她是否受益于必须捕获它们。

在这个问题上有不同的观点,但今天的主流趋势是避免检查异常(参见spring、hibernate、ApacheCommons等成功的项目)

我可以证明,今天我不再抛出已检查的异常。如果用户了解异常非常重要,那么可以在javadocs中很好地记录它,但是可以让用户自由地编写更干净的代码

编辑:我发现了一个类似的问题(以及我以前的一个答案)。可能会有帮助。

如果异常可能无法在当前方法中处理,则使用“throws”关键字,并且可以将其传播到该方法的调用方

调用方可以处理该异常,也可以使用“throws”关键字将该异常传播到另一个方法


异常类是运行时异常的基类

更多地回答主题,而不是描述:类不能使用“throws”关键字。只能使用方法和构造函数

通过一些小技巧,您可以在初始化块上使用抛出(但不是静态的)。您可以在构造函数上设置抛出,然后它将编译

public class Example{ // here you can not use throws
{
    BufferedReader in = new BufferedReader(new FileReader("asdf"));   
}   
public AbstractWithConstantsOnly() throws FileNotFoundException {   }

public static void main(String[] args) throws Exception {
    new Example();
}
}

这几乎是一场宗教辩论,但我强烈不同意没有可核查的例外的观点,因为这意味着最终有太多的例外