如果一个方法抛出了在其声明中未指定的异常,会发生什么?

25

我从未使用过“throws”子句,今天有一个朋友告诉我,在方法声明中必须指定方法可能抛出的异常。然而,我一直在使用异常而没有问题,也没有这样做,那么,如果实际上需要,为什么需要它?


你只需要指定被检查的异常(这真的很烦人)。当你未能这样做时,编译器应该会报错。 - R. Martinho Fernandes
我投票支持保留这个问题的开放状态,因为它和答案很好地涵盖了使用checkedunchecked异常的throw - AdrianHHH
6个回答

27

Java有两种不同类型的异常:checked 异常和 unchecked 异常。

Unchecked异常是RuntimeException子类,你不需要添加throws声明。所有其他异常都必须在方法体中处理,可以使用try/catch语句或者使用throws声明。

未经处理的异常示例:IllegalArgumentException,有时用于通知调用了带有非法参数的方法。无需添加 throws。

已处理的异常示例:IOException,某些来自java.io包的方法可能会抛出该异常。要么使用try/catch,要么在方法声明中添加throws IOException并将异常处理委托给方法调用者。


'throws' 关键字帮助将异常处理委托给其他组件。请参阅视频演示:http://www.bitspedia.com/2013/11/how-to-delegate-exception-handling.html - Asif Shahzad

14
如果一个方法使用 throws 关键字声明,那么任何希望调用该方法的其他方法都必须准备好捕获它或声明自己也会抛出异常。 例如,如果你想暂停应用程序,你必须调用 Thread.sleep(milliseconds); 但是这个方法的声明说它会抛出 InterruptedException 异常。 Declaration:
public static void sleep(long millis) throws InterruptedException

所以如果你想在主方法中调用它,你必须要捕获它:

public static void main(String args[]) {
    try {
        Thread.sleep(1000);
    } catch(InterruptedException ie) {
        System.out.println("Opps!");
    }
}

或者让该方法也声明它抛出一个异常:

public static void main(String args[]) throws InterruptedException {
    Thread.sleep(1000);
}

在你的最后一个例子中,我该如何捕获异常? - homerun
在我的最后一个例子中,程序将无法捕获InterruptedException,因为throws位于main()函数上。如果发生其中一个,则程序将突然结束。 - Anton

7
即使使用了“已检查”异常,这种情况仍可能发生。有时还会破坏日志记录。
假设库方法使用此技巧,允许实现可抛出IOException的Runnable。
class SneakyThrowTask implements Runnable {

    public void run() {
        throwSneakily(new IOException());
    }

    private static RuntimeException throwSneakily(Throwable ex) {
        return unsafeCastAndRethrow(ex);
    }

    @SuppressWarnings("unchecked")
    private static <X extends Throwable>X unsafeCastAndRethrow(Throwable ex) throws X {
        throw (X) ex;
    }

}

你可以这样调用它:

public static void main(String[] args) {
    try {
        new SneakyThrowTask().run();
    } catch (RuntimeException ex) {
        LOGGER.log(ex);
    }
}

这个异常不会被记录。而且因为它是一个已检查的异常,你不能写出这样的代码:

public static void main(String[] args) {
    try {
        new SneakyThrowTask().run();
    } catch (RuntimeException ex) {
        LOGGER.log(ex);
    } catch (IOException ex) {
        LOGGER.log(ex); // Error: unreachable code
    }
}

但是你会写这样的代码吗?只是想知道在什么情况下可能需要编写这样的代码。 - Sameer

4
  1. 你需要声明方法抛出的已检查异常。
  2. 如果你声明“throws Exception”,那几乎涵盖了大多数(如果不是全部)已检查异常。
  3. 你总是可以抛出未经声明的未检查运行时异常。

我很确定,如果你试图抛出一个已检查的异常,并且没有声明该方法抛出该类型的异常,代码甚至无法编译(现在正在检查)。

编辑,如果你尝试一些简单的东西,比如:

public static void main(String[] args) {
   throw new Exception("bad");
}

您遇到了编译错误。

具体来说,如果您调用一个声明为抛出异常的方法,则必须尝试/捕获该方法调用,或声明您的方法会抛出这些异常。


问题在于我不知道有检查异常和未检查异常之分。如果不是因为Andreas_D给了我完美的答案,我会接受你的回答。谢谢! - bluehallu

3
throws关键字用于将异常抛给另一个方法。
它方便了用户处理异常。因为所有的异常都可以在运行的方法中处理。
通常它主要是一个方法,所以用户不需要探索方法内部。
它还会强制throws关键字让编译器处理可能发生的异常。
如果您是API开发人员,当您编写代码时,您可能会看到异常可能会发生,因此您使用throws关键字在方法运行时处理它。

2

Java throws关键字

  • Java throws 关键字用于声明异常。
  • throws 后跟类名。
  • 可使用 throws 传播已检查异常。
  • 它向方法的调用者提供有关异常的信息。

throws 示例:

void m()throws ArithmeticException{  
    //method code  
}  

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接