尝试/捕获与引发异常


117

这些代码语句是否等效?它们之间有什么区别吗?

private void calculateArea() throws Exception {
    ....do something
}

private void calculateArea() {
    try {
        ....do something
    } catch (Exception e) {
        showException(e);
    }
}

3
并不是一个真正的答案,但是您可能会对Ned Batchelder的文章“热带雨林中异常”感兴趣,该文章有助于解释通常偏爱一种样式或另一种样式的一般情况。
丹尼尔·普里登

1
而不是在捕获中包含“ showException(e)”,您是否在问是否在捕获中包含“ throw e”(或者根本没有try / catch)?
MacGyver,2012年

Answers:


146

是的,两者之间存在巨大差异-后者吞下了异常(诚然显示了此异常),而第一个则允许其传播。(我假设showException不会将其扔掉。)

因此,如果您调用第一个方法而“执行某些操作”失败,则调用者将不得不处理该异常。如果调用第二种方法和“做什么”失败,则调用者不会看到在所有的例外......通常是一件坏事,除非showException真正处理的异常,无论固定错了,一般做肯定这calculateArea已经达到了目的。

您可以讲这个,因为你不能调用的第一个方法没有任何追赶Exception自己或者宣告你的方法可能把它太。


12
当您提到“除非它真正地处理了异常”,这是一个好点。我只是想补充一下,捕获“异常”本身很少会导致对实际异常的智能“处理”,这就是人们建议您捕获最具体的异常的原因。
Bill K

17
+1。因为乔恩·斯基特(Jon Skeet)需要更多声誉。哦,答案也很好。
Jonathan Spiller

20

首先throws Exception,因此呼叫者需要处理Exception。第二个在Exception内部捕获并处理,因此调用方不必执行任何异常处理。


简而言之,我应该始终使用第二个。我对吗?第一个实际上是一种在程序的不同点使用的方法。这就是为什么我决定gruop进一步使用说明书在一起,但已经做,我现在认识到,T为一个很大的错误..
卡洛斯-

9
不,这两种模式都是必需的。如果您的方法可以处理该异常,请使用第二种模式,否则请使用第一种模式来通知调用方。
安德里亚斯·多克

您使用哪个版本取决于您的要求-基本上需要在哪个级别上处理该异常。呼叫者需要相应地编码。如果调用方正在调用第一个版本,并且您用第二个版本替换了方法定义,则您的调用者代码将被强制处理该异常,因为这是一个已检查的异常。
samitgaur

16

是。声明的版本throws Exception将需要调用代码来处理该异常,而显式处理该版本的则不需要。

即,简单地:

performCalculation();

与将处理异常的负担转移给调用者:

try {
    performCalculation();
catch (Exception e) {
    // handle exception
}

6

是的,它们之间有很大的区别。在第一个代码块中,将异常传递给调用代码。在第二个代码块中,您可以自己处理它。哪种方法正确,完全取决于您在做什么。在某些情况下,您希望代码处理异常(例如,如果未找到文件并要创建它),但在其他情况下,您希望调用代码处理异常(未找到文件)他们需要指定一个新的或创建一个)。

通常来说,您也不想捕获通用异常。相反,您只想捕获特定的内容,例如FileNotFoundException或,IOException因为它们可能表示不同的意思。


3

在一种特殊情况下,我们不能使用throw,而必须使用try-catch。有一条规则“被覆盖的方法不能抛出其父类抛出的异常以外的任何其他异常”。如果有任何其他异常应使用try-catch处理。考虑一下此代码段。有一个简单的基类

package trycatchvsthrows;

public class Base {
    public void show()
    {
        System.out.println("hello from base");
    }
}

它是派生类:

package trycatchvsthrows;

public class Derived extends Base {

    @Override
    public void show()   {
        // TODO Auto-generated method stub
        super.show();

        Thread thread= new Thread();
        thread.start();
        try {
            thread.sleep(100);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        // thread.sleep(10);
        // here we can not use public void show() throws InterruptedException 
        // not allowed
    }
}

当我们不得不调用thread.sleep()时,我们被迫使用try-catch,在这里我们不能使用:

 public void show() throws InterruptedException

因为重写的方法不能引发额外的异常。


我相信并非所有人都知道这一警告。好点。
ivanleoncz

1

我认为“相同”是指行为。

函数的行为可以通过以下方式确定:

1)返回值

2)抛出异常

3)副作用(例如,堆,文件系统等的更改)

在这种情况下,第一种方法传播任何异常,而第二种方法则不引发任何已检查的异常,并且也吞没大多数未检查的异常,因此行为是不同的。

但是,如果保证“执行某些操作”绝不会引发异常,则行为将是相同的(尽管在第一个版本中,编译器将要求调用者处理该异常)

- 编辑 -

从API设计的角度来看,这些方法的契约完全不同。另外,不建议抛出类Exception。尝试抛出更具体的内容,以使调用方更好地处理异常。


1

如果引发异常,则子方法(将其覆盖)应处理该异常

例:

class A{
public void myMethod() throws Exception{
 //do something
}
}

A a=new A();
try{
a.myMethod();
}catch Exception(e){
//handle the exception
}

0

很多时候,您希望调用者处理异常。假设您让调用者调用了一个方法,该方法调用了另一个方法,该方法又调用了另一个方法,而不是让每个方法都处理异常,而是可以在调用方处对其进行处理。除非,当该方法失败时,您想在其中一种方法中执行某项操作。


0

该方法的调用者将需要捕获此异常或声明要在其方法签名中重新抛出该异常。

private void calculateArea() throws Exception {
    // Do something
}

在下面的try-catch块示例中。此方法的调用者不必担心处理该异常,因为它已得到处理。

private void calculateArea() {
    try {
        // Do something

    } catch (Exception e) {
        showException(e);
    }
}

0
private void calculateArea() throws Exception {
    ....do something
}

这会引发异常,因此调用方负责处理该异常,但是如果调用方不处理异常,则可能会将其提供给jvm,这可能导致异常终止程序。

而在第二种情况下:

private void calculateArea() {
    try {
        ....do something
    } catch (Exception e) {
        showException(e);
    }
}

在这里,异常是由被调用者处理的,因此程序不会异常终止。

尝试捕获是推荐的方法。

海事组织

  • Throws关键字通常与Checked异常一起使用,以说服编译器,但不能保证程序正常终止。

  • Throws关键字将异常处理的责任委托给
    调用方(JVM或其他方法)。

  • Throws关键字仅对于已检查的异常是必需的,对于未检查的异常,则不使用throws关键字。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.