在 Java 中抛出异常

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/528417/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 12:45:24  来源:igfitidea点击:

Throwing exceptions in Java

javaexception-handlingthrow

提问by user42155

I have a question about throwing exceptions in Java, a kind of misunderstanding from my side, as it seems, which I would like to clarify for myself.

我有一个关于在 Java 中抛出异常的问题,这似乎是我的一种误解,我想为自己澄清一下。

I have been reading that the two basic ways of handling exception code are:

我一直在读到处理异常代码的两种基本方法是:

1.) throwing an exception in a try-block with "throw new ...", and catching it immediately in a catch-block - the so called try-throw-catch mechanism.

1.) 在带有“throw new ...”的 try-block 中抛出异常,并立即在 catch-block 中捕获异常 - 所谓的 try-throw-catch 机制。

2.) throwing an exception in a method with "throw new ..." and then declaring in the header of the method that this method might throw an exception with "throws ..." - the so called pass-the-buck.

2.) 在带有“throw new ...”的方法中抛出异常,然后在该方法的标题中声明该方法可能会通过“throws ...”抛出异常 - 所谓的pass-the-buck。

I have recently read that "it doesn't make any sense to throw an exception and then catch it in the same method", which made me think whether I understand the thing in the wrong way, or the person who had written this had something else in mind. Doesn't the first way of handling exceptions does exactly this (the try-throw-catch mechanism) ? I mean, it throws an exception and catches it in the same method. I have read that it is a better practice to throw an exception in one method, and catch it in another method, but this is just one (probably better) way. The other way is also legal and correct, isn't it?

我最近读到“抛出异常然后用同样的方法捕获它没有任何意义”,这让我思考是否我以错误的方式理解了这件事,或者写这篇文章的人有什么东西其他的。处理异常的第一种方法不正是这样做的(try-throw-catch 机制)吗?我的意思是,它抛出一个异常并以相同的方法捕获它。我已经读到在一种方法中抛出异常并在另一种方法中捕获它是一种更好的做法,但这只是一种(可能更好)的方法。另一种方式也是合法正确的,不是吗?

Would you, please, give me a comment on this ? Thank you very much.

请你给我评论一下好吗?非常感谢你。

回答by David Koelle

Exceptions should be thrown from a method when that method is incapable of resolving the exception on its own.

当该方法无法自行解决异常时,应该从该方法中抛出异常。

For example, a FileNotFoundExceptionis thrown from new FileInputStream(new File(filename))because the FileInputStream itself can't handle a case where a file is missing; that exception needs to get thrown so the end-user application can handle the problem.

例如,FileNotFoundException抛出a是因为 FileInputStream 本身无法处理文件丢失的情况;需要抛出该异常,以便最终用户应用程序可以处理该问题。new FileInputStream(new File(filename))

There are some cases where exceptions could be handled within a method. For example, a Document model method throwing a BadLocationExceptioncould be handled within a sufficiently intelligent method. Depending on the problem, either the exception can be handled or re-thrown.

在某些情况下,可以在方法中处理异常。例如,BadLocationException可以在足够智能的方法中处理抛出 a 的 Document 模型方法。根据问题,可以处理或重新抛出异常。

(Anyway, I'd argue that throwing an exception from within a try-catch block so the catch block can be executed represents really bad logic flow)

(无论如何,我认为从 try-catch 块中抛出异常以便可以执行 catch 块代表非常糟糕的逻辑流程)

回答by starblue

I think you misunderstood the first case. Normally you add a try-catch-block when you call some method which may throw exceptions. Catching locally thrown exceptions indeed doesn't make much sense. In particular you shouldn't use exceptions to exit from loops, as this is extremely slow compared to a standard approach.

我想你误解了第一种情况。通常,当您调用某些可能引发异常的方法时,您会添加一个 try-catch-block。捕获本地抛出的异常确实没有多大意义。特别是您不应该使用异常退出循环,因为与标准方法相比,这非常慢。

回答by Michael Borgwardt

Doesn't the first way of handling exceptions does exactly this (the try-throw-catch mechanism)? I mean, it throws an exception and catches it in the same method.

处理异常的第一种方法不正是这样做的(try-throw-catch 机制)吗?我的意思是,它抛出一个异常并以相同的方法捕获它。

That's not a "way of handling exceptions" - it's utter nonsense. The whole point of exceptions is to let another method up the call stack handle it. If you're going to handle the condition within the same method, there's no point in using an exception - that's what if() is for! If that makes the control flow of your method too complicated, you should probably refactor some of the logic into separate methods - and then it might make sense to have those throw exception that the remaining method body catches.

这不是“处理异常的方式”——这完全是胡说八道。异常的全部意义在于让调用堆栈上的另一个方法处理它。如果您打算在同一个方法中处理条件,那么使用异常是没有意义的——这就是 if() 的用途!如果这使您的方法的控制流过于复杂,您可能应该将某些逻辑重构为单独的方法 - 然后让其余方法主体捕获的抛出异常可能是有意义的。

That being said, I can imagine one special case where it could make sense to throw and catch an exception in the same method: when you're already calling a method that may throw an exception and have a catch block to handle it, then in some cases it could make sense to throw an exception to indicate a similar problem that the existing catch block can handle in the same way.

话虽如此,我可以想象一种特殊情况,在这种情况下,在同一方法中抛出和捕获异常是有意义的:当您已经调用了一个可能抛出异常并有一个 catch 块来处理它的方法时,然后在在某些情况下,抛出异常以指示现有 catch 块可以以相同方式处理的类似问题可能是有意义的。

回答by DJClayworth

The person who wrote "it doesn't make any sense to throw an exception and then catch it in the same method" is entitled to their opinion, but it's not widely shared. There are plenty of cases where throwing and catching an exception in the same method is what's needed. The simplest is where you are doing a sequence of operations and the failure of any one of them makes the rest invalid. If you detect that one of these operations fails it's perfectly reasonable to throw an exception and catch it at the end of the method. In fact it's the logical way of doing things. Arguably you could rewrite the code to not use the exception, maybe with some status flags and a break statement or two, but why would you? Using an exception makes it clear what's going on and improves code readability.

写“抛出异常然后用相同的方法捕获它没有任何意义”的人有权发表他们的意见,但并没有被广泛分享。在很多情况下,需要在同一方法中抛出和捕获异常。最简单的是您正在执行一系列操作,其中任何一个失败都会使其余操作无效。如果您检测到这些操作之一失败,则抛出异常并在方法结束时捕获它是完全合理的。事实上,这是做事的逻辑方式。可以说,您可以重写代码以不使用异常,也许使用一些状态标志和一两个中断语句,但为什么要这样做呢?使用异常可以清楚地了解正在发生的事情并提高代码的可读性。

回答by Ed Gonzalez

I'm gonna answer your questions in turn, then add some comments to the end. I'm not an authority on exception handling, but I hope my comments are helpful.

我将依次回答您的问题,然后在最后添加一些评论。我不是异常处理的权威,但我希望我的评论有帮助。



"Doesn't the first way of handling exceptions does exactly this"?

“处理异常的第一种方法不正是这样做的吗”?

My answer is yes, as you describe it the first method does operate by throwing and catching an exception in the same method. However, I don't know that try-throw-catch has to work as you describe it.

我的回答是肯定的,正如您所描述的,第一种方法确实通过在同一方法中抛出和捕获异常来进行操作。但是,我不知道 try-throw-catch 必须像您描述的那样工作。



"I have read that it is a better practice to throw an exception in one method, and catch it in another method, but this is just one (probably better) way. The other way is also legal and correct, isn't it?"

“我读过,在一种方法中抛出异常并在另一种方法中捕获它是一种更好的做法,但这只是一种(可能更好)的方式。另一种方式也是合法和正确的,不是吗? ”

I agree that catching exceptions from a second method is better, but the first way is legal. Is it correct? well that's for you to decide, it is your code, after all.

我同意从第二种方法捕获异常更好,但第一种方法是合法的。这是正确的吗?好吧,这由您决定,毕竟这是您的代码。

For the most part, I agree that it doesn't make sense to throw an exception then immediately catch that exception in the same method. If we do this because the method is particularly long/complex and handling the error using other logic would complicate things more, then I would suggest moving some of this logic to another method and calling that method and catching its exception.

在大多数情况下,我同意抛出异常然后立即在同一方法中捕获该异常是没有意义的。如果我们这样做是因为该方法特别长/复杂并且使用其他逻辑处理错误会使事情变得更加复杂,那么我建议将某些逻辑移到另一个方法并调用该方法并捕获其异常。

If our code is simpler, then it may be easy to handle the error using code that doesn't consist of throwing an exception.

如果我们的代码更简单,那么使用不包含抛出异常的代码来处理错误可能很容易。



My comments:

我的评论:

The try-throw-catch mechanism you mentioned may not need the exception to be thrown in the same method. I would have to read the text you found to be certain, but I would expect that it isn't necessary. If it didn't need the exception to be thrown in the same method, then your exceptions handling strategy is a combination of 1) and 2).

你提到的 try-throw-catch 机制可能不需要在同一个方法中抛出异常。我将不得不阅读您认为确定的文本,但我认为这不是必需的。如果它不需要在同一个方法中抛出异常,那么你的异常处理策略是 1) 和 2) 的组合。

In the combo, one method would use try-throw-catch mechanism to catch an exception thrown by a called method. It seems to me that 1) and 2) should work together to form your exception handling strategy.

在组合中,一种方法将使用 try-throw-catch 机制来捕获被调用方法抛出的异常。在我看来,1) 和 2) 应该一起工作以形成您的异常处理策略。

Now, maybe someone will come along and give us some wonderful reasons why we might want to throw an exception in the same method. I expect there are some, but to me they seem the exceptions, not the rule.

现在,也许有人会过来给我们一些很好的理由,为什么我们可能想在同一个方法中抛出异常。我希望有一些,但对我来说,它们似乎是例外,而不是规则。

Cheers, Ed

干杯,埃德

回答by kgiannakakis

With the first way do you mean something like this:

第一种方式你的意思是这样的:

try {
  ok = doSomething();
  if (!ok) {
   throw new Exception("Error");
  }
 ok = doSomethingElse();
}catch (Exception e) {
}

This will allow you to exit the try-catch block without executing the rest of it. This is the only valid usage I can think of throwing an exception with throw and catching it yourself in a try-catch block. However, standard if blocks should be used instead. I don't understand why someone should throw an exception and then catch it himself.

这将允许您退出 try-catch 块而不执行它的其余部分。这是我能想到的唯一有效的用法是用 throw 抛出异常并在 try-catch 块中自己捕获它。但是,应改用标准 if 块。我不明白为什么有人应该抛出异常然后自己捕获它。

The second way is more standard, especially if the caller of the method that throws an exception is an external module. This is a way of signaling that something real wrong happened. It is the responsibility of the caller to handle the exception.

第二种方式更标准,尤其是当抛出异常的方法的调用者是外部模块时。这是一种表明发生了真正错误的方式。处理异常是调用者的责任。

回答by Scott Saunders

If you're going to manually throw an exception, then obviously you know there has been some error that needs to be handled. Rather than throw the new exception, then catch it, then immediately handle the error, why not just handle the error? You (and the processor) don't need to go through all the work of generating an exception and catching it. The exception also makes the code harder to read and debug.

如果您要手动抛出异常,那么显然您知道存在一些需要处理的错误。与其抛出新的异常,然后捕获它,然后立即处理错误,为什么不直接处理错误呢?您(和处理器)不需要完成生成异常和捕获异常的所有工作。该异常还使代码更难阅读和调试。

You would throw an exception, rather than just handling the error immediately, if:

如果出现以下情况,您将抛出异常,而不是立即处理错误:

  • Other code, like the code that called your method, should handle the error. For example, if your code is not UI code, then it probably shouldn't generate windows. This is your method #2.

  • You can take advantage of the try, catch, finally block. It's possible that you could write cleaner code this way, but I think that 90% of the time your code would be more readable using simple if statements.

  • 其他代码,如调用您的方法的代码,应该处理错误。例如,如果您的代码不是 UI 代码,那么它可能不应该生成窗口。这是你的方法#2。

  • 您可以利用 try、catch 和 finally 块。您可能可以通过这种方式编写更清晰的代码,但我认为在 90% 的情况下,使用简单的 if 语句您的代码将更具可读性。

回答by Jeff Olson

Using an exception for control flow is specifically dealt with in Effective Java, 2nd Editionby Joshua Bloch, Item 57:

Joshua Bloch在Effective Java,第 2 版,第 57 条中专门讨论了使用异常进行控制流:

Item 57: Use exceptions only for exceptional conditions

第 57 条:仅在异常情况下使用异常

...exceptions are, as their name implies, to be used only for exceptional conditions; they should never be used for ordinary control flow. [italics mine]

...异常,顾名思义,仅用于特殊情况;它们永远不应该用于普通的控制流。[斜体我的]

So while it certainly "works" to use exceptions to control flow, it is not recommended.

因此,虽然使用异常来控制流肯定“有效”,但不建议这样做。

回答by Gambrinus

My expierence is that using the first method gets your code quickly unreadable - since the functionality and the error-handling is getting mixed up. BUTit makes sense in some cases where you have a try{}catch{}finaly{} - for example in file handling or database handling where you ALLWAYSwant the connection to be closed.

我的经验是,使用第一种方法会使您的代码很快变得不可读 - 因为功能和错误处理正在混淆。在某些情况下,您有 try{}catch{}finaly{} 是有意义的 - 例如在文件处理或数据库处理中,您总是希望关闭连接。

try{ //do something
}catch(Exception ex){
//log
}finally{
//connection.close
}

For everything else I use the second option - just for the reason to centralize my error-handling routines and keep the readability of the code implementing the businesslogic itself.

对于其他一切,我使用第二个选项 - 只是为了集中我的错误处理例程并保持实现业务逻辑本身的代码的可读性。

回答by duffymo

In my opinion, try blocks that you write should not include any "throw new" that are caught inside the same method. When you throw an exception, you're saying "I've encountered a situation that I can't handle; somebody else will have to deal with it." Your method with the "throw new" should either create an unchecked exception to throw or declare a checked exception in its method signature.

在我看来,您编写的 try 块不应包含在同一方法中捕获的任何“throw new”。当您抛出异常时,您是在说“我遇到了我无法处理的情况;其他人将不得不处理它。” 带有“throw new”的方法应该创建一个未经检查的异常来抛出或在其方法签名中声明一个已检查的异常。

If you're using 3rd party classes that may throw exceptions, your method should have a try/catch block if you can actually handle the situation if an exception arises. Otherwise, you should defer to another class that can.

如果您正在使用可能引发异常的 3rd 方类,并且您的方法应该有一个 try/catch 块,如果您可以在出现异常时实际处理这种情况。否则,您应该遵循另一个可以的课程。

I don't create my own exception and then catch it in the same method.

我不会创建自己的异常,然后用相同的方法捕获它。