Java 为什么 Catch(Exception) 几乎总是一个坏主意?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2416316/
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-08-13 07:19:27  来源:igfitidea点击:

Why is the Catch(Exception) almost always a bad Idea?

javaexceptionexception-handling

提问by Nasser Hadjloo

Why is the catch(Exception)almost always a bad Idea?

为什么catch(Exception)几乎总是一个坏主意?

采纳答案by anthares

Because when you catch exception you're supposed to handle it properly. And you cannot expect to handle all kind of exceptions in your code. Also when you catch all exceptions, you may get an exception that cannot deal with and prevent code that is upper in the stack to handle it properly.

因为当您捕获异常时,您应该正确处理它。并且您不能期望在您的代码中处理所有类型的异常。此外,当您捕获所有异常时,您可能会得到一个异常,该异常无法处理并阻止堆栈中的上层代码正确处理它。

The general principal is to catch the most specific type you can.

一般原则是尽可能捕捉最具体的类型。

回答by Lucero

Because you don't really know why an exception happened, and several exceptions require very special car to be handled correctly (if possible at all), such as a OutOfMemoryException and similar low-level system exceptions.

因为你真的不知道为什么会发生异常,并且有几个异常需要非常特殊的汽车才能正确处理(如果可能的话),例如 OutOfMemoryException 和类似的低级系统异常。

Therefore, you should only catch exceptions:

因此,您应该只捕获异常:

  • which you know exactly how to deal with it (e.g. FileNotFoundException or so)
  • when you will re-raise them afterwards (for instance to perform post-fail cleanup)
  • when you need to transport the exception to another thread
  • 您确切知道如何处理它(例如 FileNotFoundException 左右)
  • 之后何时重新加注(例如执行失败后清理)
  • 当您需要将异常传输到另一个线程时

回答by Andrew Bezzub

It depends on what you need. If you need to handle different types of exceptions in different ways then you should use multiple catch blocks and catch as much specific exceptions as you can.

这取决于你需要什么。如果您需要以不同的方式处理不同类型的异常,那么您应该使用多个 catch 块并尽可能多地捕获特定的异常。

But sometimes you may need to handle all exceptions in the same way. In such cases catch(Exception) may be ok. For example:

但有时您可能需要以相同的方式处理所有异常。在这种情况下 catch(Exception) 可能没问题。例如:

    try
    {
        DoSomething();
    }
    catch (Exception e)
    {
        LogError(e);
        ShowErrorMessage(e); // Show "unexpected error ocurred" error message for user.
    }

回答by Darin Dimitrov

You should only catch exceptions if you can properly handle them. As you cannot properly handle all possible exceptions you should not catch them :-)

如果您可以正确处理它们,您应该只捕获异常。由于您无法正确处理所有可能的异常,因此不应捕获它们:-)

回答by dimitarvp

Short story: it's called bug masking. If you have a piece of code which is not working well and throwing exceptions (or you pass malformed input to that piece of code) and you just blind your eyes by catching all possible exceptions, you will actually never uncover the bug and fix it.

简短的故事:它被称为错误屏蔽。如果您有一段代码运行不正常并抛出异常(或者您将格式错误的输入传递给那段代码),而您只是通过捕获所有可能的异常来蒙蔽双眼,您实际上永远不会发现错误并修复它。

回答by Vincent Fleetwood

This may be java specific:

这可能是特定于 Java 的:

Sometimes you will need to call methods that throw checked exceptions. If this is in your EJB / business logic layer you have 2 choices - catch them or re-throw them.

有时您需要调用抛出已检查异常的方法。如果这是在您的 EJB / 业务逻辑层中,您有 2 个选择 - 抓住它们或重新抛出它们。

Catching specific exception classes means you will need to re-analyze your actions for which exceptions can be thrown when you look to see how this code handles exceptions. You will often get into a "what if..." situation and it can be a lot of effort just working out if exceptions are handled correctly.

捕获特定的异常类意味着当您查看此代码如何处理异常时,您将需要重新分析可以抛出异常的操作。您经常会遇到“假设……”的情况,如果正确处理异常,就需要付出很多努力。

Re-throwing means that code calling your EJBs will be littered with catching code that will typically not mean anything to the calling class. n.b. throwing checked exceptions from EJB methods will mean that you are responsible for manually rolling back any transactions.

重新抛出意味着调用您的 EJB 的代码将充斥着捕获代码,这些代码通常对调用类没有任何意义。nb 从 EJB 方法抛出已检查的异常将意味着您负责手动回滚任何事务。

回答by taringamberini

Besides what yet answered by @anthares:

除了@anthares 尚未回答的内容:

Because when you catch exception you're supposed to handle it properly. And you cannot expect to handle all kind of exceptions in your code. Also when you catch all exceptions, you may get an exception that cannot deal with and prevent code that is upper in the stack to handle it properly.

The general principal is to catch the most specific type you can.

因为当您捕获异常时,您应该正确处理它。并且您不能期望在您的代码中处理所有类型的异常。此外,当您捕获所有异常时,您可能会得到一个异常,该异常无法处理并阻止堆栈中的上层代码正确处理它。

一般原则是尽可能捕捉最具体的类型。

catch(Exception)is a bad practice because it catches all RuntimeException (unchecked exception) too.

catch(Exception)是一种不好的做法,因为它也会捕获所有 RuntimeException(未经检查的异常)。

回答by MattC

But sometimes it is OK! Like if you have a piece of code that does something 'extra', which you really don't care about, and you don't want it to blow up your application. For example, I worked on a large application recently where our business partners wanted a certain daily transaction to be summarized in a new log file. They explained that the log wasn't all that important to them, and that it did not qualify as a requirement. It was just something extra that would help them make sense of the data being processed. They did not need it, because they could get the information elsewhere. So that is a rare case where it is perfectly fine to catch and swallow exceptions.

但有时是可以的!就像你有一段代码做了一些“额外”的事情,你真的不关心,你不希望它炸毁你的应用程序。例如,我最近在一个大型应用程序中工作,我们的业务合作伙伴希望将某个日常事务汇总到一个新的日志文件中。他们解释说,日志对他们来说并不是那么重要,而且它不符合要求。这只是一些额外的东西,可以帮助他们理解正在处理的数据。他们不需要它,因为他们可以从其他地方获得信息。所以这是一种罕见的情况,捕获和吞下异常是完全没问题的。

I also worked at a company where all Throwables were caught, and then rethrown inside a custom RuntimeException. I would not recommend this approach, but just pointing out that it is done.

我还在一家公司工作过,所有 Throwables 都被捕获,然后在自定义 RuntimeException 中重新抛出。我不会推荐这种方法,但只是指出它已经完成。

回答by lujop

I find two acceptable uses of catch(Exception):

我发现有两种可接受的用法catch(Exception)

  • At the top level of the application (just before returning to the user). That way you can provide an adequate message.
  • Using it to mask low-level exceptions as business ones.
  • 在应用程序的顶层(就在返回给用户之前)。这样你就可以提供足够的信息。
  • 使用它将低级异常屏蔽为业务异常。

The first case is self-explanatory, but let me develop the second:

第一种情况不言自明,但让我开发第二种情况:

Doing:

正在做:

try {
    // xxxx
} catch(Exception e) {
    logger.error("Error XXX",e)
}

is bug masking like @dimitarvp said.

是像@dimitarvp 所说的错误屏蔽。

But the below is different:

但是下面的就不一样了:

try {
    // xxxx
} catch(Exception e) {
    throw new BussinessException("Error doing operation XXX",e)
}

This way you aren't ignoring bugs and hiding them under the carpet. You are providing a high-level exception with a more explanatory message to higher application layers.

这样您就不会忽略错误并将它们隐藏在地毯下。您正在向更高的应用程序层提供带有更具解释性的消息的高级异常。

It's also always important to manage exceptions at the correct layer. If you escalate a low-level exception to a high business layer, it's practically impossible for the higher layer to manage it well.

在正确的层管理异常也总是很重要的。如果将低级异常升级到高级业务层,则更高层实际上不可能很好地管理它。

In that case, I prefer to mask the low level exceptions with a business one that provides a better context and message and that also has the original exception to be able to go into the details.

在这种情况下,我更喜欢使用提供更好上下文和消息的业务异常来掩盖低级别异常,并且该异常也具有能够进入细节的原始异常。

Even so, if you can catch more concrete exceptions and provide better treatment for them you must do it.

即便如此,如果您可以捕获更具体的异常并为它们提供更好的处理,您就必须这样做。

If in a block of code you can get an SQLExceptionand a NetworkExceptionyou must catch them and provide adequate messages and treatment for each of them. But if at the end of the try/catch block you have an Exceptionmapping it to a BussinessExceptionit's ok for me. In fact, I find it adequate when higher service layers only throw business exceptions (with details inside).

如果在代码块中可以得到 anSQLException和 a NetworkException,则必须捕获它们并为它们中的每一个提供足够的消息和处理。但是如果在 try/catch 块的末尾你有一个Exception映射到 aBussinessException对我来说没问题。事实上,当更高的服务层只抛出业务异常(里面有详细信息)时,我觉得就足够了。

回答by opfau

Isn't it another valid scenario to ensure that a thread keeps alive catching exception inside it?

确保线程保持活动状态以捕获其中的异常难道不是另一个有效的场景吗?

Thread shouldRunWhenApplicationRuns = new Thread() {
    @Override
    public void run() {
        try {
            // do something that should never end
        } catch (Exception ex) {
            // log it
        }
    };
    shouldRunWhenApplicationRuns.start();