什么时候应该检查异常/未选中的异常?

时间:2022-03-04 20:35:23

I have learned from various tutorial that "If a client can reasonably be expected to recover from an exception, make it a checked exception. If a client cannot do anything to recover from the exception, make it an unchecked exception."

我从各种教程中学到了“如果可以合理地期望客户端从异常中恢复,请将其作为检查异常。如果客户端无法执行任何操作以从异常中恢复,请将其作为未经检查的异常。”

I really want to see the effectiveness of previous statement through some code examples. e.g.

我真的希望通过一些代码示例看到先前语句的有效性。例如

try {
        br.readLine();
    } catch (IOException e) {

        e.printStackTrace();
    }

Here, IOException is checked Exception.So, how I'm supposed to recover when this Exception occurs? Here, I'm excluding the exception logging,exception re-throwing tasks since they are not actually recovering i.e making things right. So, what modification should be applied here to recover from it?

在这里,IOException被检查Exception.So,当这个异常发生时,我应该如何恢复?在这里,我排除异常记录,异常重新抛出任务,因为它们实际上并没有恢复,即正确的事情。那么,应该在这里应用哪些修改来从中恢复?

If there's a way to recover from it, then the same kind of approach can be applied to the following code :

如果有办法从中恢复,那么同样的方法可以应用于以下代码:

 try{
    Integer.parseInt("ghg4");
 }catch(NumberFormatException nfe){   
   }

Here NumberFormatException is a Runtime/unchecked exception.So if there's a way to recover from it, then why is it declared as Runtime exception in the first place?

这里NumberFormatException是一个运行时/未经检查的异常。如果有办法从中恢复,那么为什么它首先被声明为运行时异常?

3 个解决方案

#1


1  

I see three types of exceptions. At the one extreme are the ones you can't do anything about, like a NullPointerException. You're going to handle this at a very high level in your code or not at all. It would be ridiculous to check it.

我看到三种类型的例外。在一个极端是你无法做任何事情,如NullPointerException。您将在代码中以非常高的级别处理此问题,或者根本不处理。检查它是荒谬的。

At the other end are the ones that provide meaningful information. They're sort of a way of returning a value, sometimes a complex one, when the method already has a return value. They're also an easy way of jumping up the call stack. (I could write a book about this, but I'll stop here.) An EOFException ought to be a good example of this. Files have their ends, you're going to hit it sooner or later, and you don't want to have to check it every time you do a read. In this case, a checked exception is called for. (I think user1291492 would agree with me on this.) It can happen, and anybody calling a read method should be prepared for it. They'll much prefer a compiler error to a runtime error.

另一端是提供有意义信息的那些。当方法已经具有返回值时,它们有点返回值,有时是复数值。它们也是一种跳跃调用堆栈的简单方法。 (我可以写一本关于这个的书,但我会在这里停下来。)EOFException应该是一个很好的例子。文件有它们的目的,你迟早会打它,你不想每次读取它都要检查它。在这种情况下,将调用已检查的异常。 (我认为user1291492会就此与我达成一致。)它可能会发生,任何调用read方法的人都应该为此做好准备。他们更喜欢编译器错误而不是运行时错误。

Now, with this type of exception, you do not want to put in a stack trace!!! It costs lots of time. The caller just needs to know he hit an EOF, not where in the depths of the IO system it happened! Further, unless there is interesting information to be returned, the exception itself ought to be a final static reference, generated once and used for every EOF that happens.

现在,有了这种类型的异常,你不想放入堆栈跟踪!这需要很多时间。调用者只需知道他打了一个EOF,而不是发生在IO系统的深处!此外,除非要返回有趣的信息,否则异常本身应该是最终的静态引用,生成一次并用于发生的每个EOF。

The third type, in the middle, are the ones the Java libraries use, like the real EOFException. They make no sense. Either the caller expects never to get an EOF (he put his own marker out there, for instance) and EOFException is of the same nature as a NullPointerException, or he expects it and doesn't need the hassle and lost processing time of a stack trace. I think the problem is that the Java designers themselves--and I have to admit to having this problem myself when I think about it--which is rarely--weren't sure which of the first two categories these exceptions might fall into. Even in the same program, in one place the EOFException might indicate the total failure of a program. In another, it might be the normal way to find out that a file has been read. So the end result is a ton of exceptions that do both jobs and do them poorly, forcing the programmer to use try and catch and throws when they can't do anything anyway and handing them elaborate stack traces they don't need.

第三种类型,在中间,是Java库使用的类型,如真正的EOFException。他们毫无意义。调用者期望永远不会得到EOF(例如,他将自己的标记放在那里),并且EOFException与NullPointerException具有相同的性质,或者他期望它并且不需要堆栈的麻烦和丢失的处理时间跟踪。我认为问题在于Java设计者本身 - 而且我不得不承认在我考虑这个问题时自己遇到这个问题 - 这很少 - 不确定这两个类别中的哪两个可能属于这些例外。即使在同一个程序中,在一个地方,EOFException也可能表示程序完全失败。在另一种情况下,可能是找出文件已被读取的常规方法。因此,最终的结果是大量的异常会同时完成这两项工作并且做得很差,迫使程序员在他们无法做任何事情时使用try和catch并抛出它们并将它们不需要的复杂堆栈跟踪交给他们。

Addition: I should pehaps note explicitly that you can recover from the real EOFException by simply accepting that you have finished reading the file and carrying on, possibly with a break statement in the catch block. However, there are other, proper ways to catch an EOF, so an EOFException usually means a real problem like a NullPointerException. Oddly, the way I use NumberFormatException, I think it should be checked. Getting "AAA" when I want a number is very common, a user error, not a programming error.

另外:我应该明确指出,您可以通过简单地接受已经完成读取文件并继续执行来恢复真正的EOFException,可能在catch块中使用break语句。但是,还有其他正确的方法来捕获EOF,因此EOFException通常意味着像NullPointerException这样的真正问题。奇怪的是,我使用NumberFormatException的方式,我认为应该检查。当我想要一个数字时获得“AAA”是非常常见的,用户错误,而不是编程错误。

#2


1  

c# did away with checked exceptions, which I think was a good idea.

c#消除了检查异常,我认为这是一个好主意。

In code that I've written, I have mostly followed the c# pattern, extending everything from RuntimeException. However there are a few places where I have utilized checked exceptions to force myself and anyone using my code to respond to what is more of a "normal" exceptional condition

在我编写的代码中,我主要遵循c#模式,从RuntimeException扩展所有内容。然而,有一些地方我利用已检查的异常来强制自己和任何使用我的代码的人回应更多的“正常”异常情况

#3


1  

There is no explicit border between RuntimeException and Exception. Generally speaking, overusing descendants of Exception leads either to chains of catch clauses (e.g. for reflection handling code) or just catch (Exception e) which doesn't care about particular types. There are many different practices and this question is controversial - i.e. it's not that simple and there is no the only one right way to design exceptions in your application.

RuntimeException和Exception之间没有明确的边界。一般来说,过度使用Exception的后代会导致catch子句链(例如反射处理代码)或者只捕获(Exception e)而不关心特定类型。有许多不同的做法,这个问题是有争议的 - 即它并不那么简单,并且没有唯一一种正确的方法来设计应用程序中的异常。


I keep the following rule:

我遵守以下规则:

  1. If an exception is going to be handled separately and is distinguishable from a simple input data error or something like that - it's a checked exception.

    如果异常将单独处理并且可以与简单的输入数据错误或类似错误区分开来 - 它是一个经过检查的异常。

  2. If an exception is caused by obviously wrong input conditions or bug in the code (like NPE) - then it's runtime exception.

    如果异常是由明显错误的输入条件或代码中的错误(如NPE)引起的 - 那么它就是运行时异常。

From this logic, for example, I would have made IOException a descendant of RuntimeException.

例如,从这个逻辑来看,我会将IOException作为RuntimeException的后代。


UPDATE: This is not black and white regarding IOException. But some of IOE descendants (like FileNotFoundException, MalformedURLException etc.) - are definitely just bad input. Also it makes things annoying when you work with ByteArray IO Streams (or similar ones) to handle IOE which never happen.

更新:关于IOException,这不是黑白分明的。但是一些IOE后代(如FileNotFoundException,MalformedURLException等) - 肯定只是糟糕的输入。当你使用ByteArray IO Streams(或类似的)来处理从未发生过的IOE时,它会让事情变得烦人。

#1


1  

I see three types of exceptions. At the one extreme are the ones you can't do anything about, like a NullPointerException. You're going to handle this at a very high level in your code or not at all. It would be ridiculous to check it.

我看到三种类型的例外。在一个极端是你无法做任何事情,如NullPointerException。您将在代码中以非常高的级别处理此问题,或者根本不处理。检查它是荒谬的。

At the other end are the ones that provide meaningful information. They're sort of a way of returning a value, sometimes a complex one, when the method already has a return value. They're also an easy way of jumping up the call stack. (I could write a book about this, but I'll stop here.) An EOFException ought to be a good example of this. Files have their ends, you're going to hit it sooner or later, and you don't want to have to check it every time you do a read. In this case, a checked exception is called for. (I think user1291492 would agree with me on this.) It can happen, and anybody calling a read method should be prepared for it. They'll much prefer a compiler error to a runtime error.

另一端是提供有意义信息的那些。当方法已经具有返回值时,它们有点返回值,有时是复数值。它们也是一种跳跃调用堆栈的简单方法。 (我可以写一本关于这个的书,但我会在这里停下来。)EOFException应该是一个很好的例子。文件有它们的目的,你迟早会打它,你不想每次读取它都要检查它。在这种情况下,将调用已检查的异常。 (我认为user1291492会就此与我达成一致。)它可能会发生,任何调用read方法的人都应该为此做好准备。他们更喜欢编译器错误而不是运行时错误。

Now, with this type of exception, you do not want to put in a stack trace!!! It costs lots of time. The caller just needs to know he hit an EOF, not where in the depths of the IO system it happened! Further, unless there is interesting information to be returned, the exception itself ought to be a final static reference, generated once and used for every EOF that happens.

现在,有了这种类型的异常,你不想放入堆栈跟踪!这需要很多时间。调用者只需知道他打了一个EOF,而不是发生在IO系统的深处!此外,除非要返回有趣的信息,否则异常本身应该是最终的静态引用,生成一次并用于发生的每个EOF。

The third type, in the middle, are the ones the Java libraries use, like the real EOFException. They make no sense. Either the caller expects never to get an EOF (he put his own marker out there, for instance) and EOFException is of the same nature as a NullPointerException, or he expects it and doesn't need the hassle and lost processing time of a stack trace. I think the problem is that the Java designers themselves--and I have to admit to having this problem myself when I think about it--which is rarely--weren't sure which of the first two categories these exceptions might fall into. Even in the same program, in one place the EOFException might indicate the total failure of a program. In another, it might be the normal way to find out that a file has been read. So the end result is a ton of exceptions that do both jobs and do them poorly, forcing the programmer to use try and catch and throws when they can't do anything anyway and handing them elaborate stack traces they don't need.

第三种类型,在中间,是Java库使用的类型,如真正的EOFException。他们毫无意义。调用者期望永远不会得到EOF(例如,他将自己的标记放在那里),并且EOFException与NullPointerException具有相同的性质,或者他期望它并且不需要堆栈的麻烦和丢失的处理时间跟踪。我认为问题在于Java设计者本身 - 而且我不得不承认在我考虑这个问题时自己遇到这个问题 - 这很少 - 不确定这两个类别中的哪两个可能属于这些例外。即使在同一个程序中,在一个地方,EOFException也可能表示程序完全失败。在另一种情况下,可能是找出文件已被读取的常规方法。因此,最终的结果是大量的异常会同时完成这两项工作并且做得很差,迫使程序员在他们无法做任何事情时使用try和catch并抛出它们并将它们不需要的复杂堆栈跟踪交给他们。

Addition: I should pehaps note explicitly that you can recover from the real EOFException by simply accepting that you have finished reading the file and carrying on, possibly with a break statement in the catch block. However, there are other, proper ways to catch an EOF, so an EOFException usually means a real problem like a NullPointerException. Oddly, the way I use NumberFormatException, I think it should be checked. Getting "AAA" when I want a number is very common, a user error, not a programming error.

另外:我应该明确指出,您可以通过简单地接受已经完成读取文件并继续执行来恢复真正的EOFException,可能在catch块中使用break语句。但是,还有其他正确的方法来捕获EOF,因此EOFException通常意味着像NullPointerException这样的真正问题。奇怪的是,我使用NumberFormatException的方式,我认为应该检查。当我想要一个数字时获得“AAA”是非常常见的,用户错误,而不是编程错误。

#2


1  

c# did away with checked exceptions, which I think was a good idea.

c#消除了检查异常,我认为这是一个好主意。

In code that I've written, I have mostly followed the c# pattern, extending everything from RuntimeException. However there are a few places where I have utilized checked exceptions to force myself and anyone using my code to respond to what is more of a "normal" exceptional condition

在我编写的代码中,我主要遵循c#模式,从RuntimeException扩展所有内容。然而,有一些地方我利用已检查的异常来强制自己和任何使用我的代码的人回应更多的“正常”异常情况

#3


1  

There is no explicit border between RuntimeException and Exception. Generally speaking, overusing descendants of Exception leads either to chains of catch clauses (e.g. for reflection handling code) or just catch (Exception e) which doesn't care about particular types. There are many different practices and this question is controversial - i.e. it's not that simple and there is no the only one right way to design exceptions in your application.

RuntimeException和Exception之间没有明确的边界。一般来说,过度使用Exception的后代会导致catch子句链(例如反射处理代码)或者只捕获(Exception e)而不关心特定类型。有许多不同的做法,这个问题是有争议的 - 即它并不那么简单,并且没有唯一一种正确的方法来设计应用程序中的异常。


I keep the following rule:

我遵守以下规则:

  1. If an exception is going to be handled separately and is distinguishable from a simple input data error or something like that - it's a checked exception.

    如果异常将单独处理并且可以与简单的输入数据错误或类似错误区分开来 - 它是一个经过检查的异常。

  2. If an exception is caused by obviously wrong input conditions or bug in the code (like NPE) - then it's runtime exception.

    如果异常是由明显错误的输入条件或代码中的错误(如NPE)引起的 - 那么它就是运行时异常。

From this logic, for example, I would have made IOException a descendant of RuntimeException.

例如,从这个逻辑来看,我会将IOException作为RuntimeException的后代。


UPDATE: This is not black and white regarding IOException. But some of IOE descendants (like FileNotFoundException, MalformedURLException etc.) - are definitely just bad input. Also it makes things annoying when you work with ByteArray IO Streams (or similar ones) to handle IOE which never happen.

更新:关于IOException,这不是黑白分明的。但是一些IOE后代(如FileNotFoundException,MalformedURLException等) - 肯定只是糟糕的输入。当你使用ByteArray IO Streams(或类似的)来处理从未发生过的IOE时,它会让事情变得烦人。