简体   繁体   English

当我们需要抛出自定义异常时,如何防止异常捕获?

[英]How to prevent exception catching when we need to throw custom exceptions?

  void connectOverNetwork() throws Exception {
    try {
      final JSONObject response = make network call;

      if (!response.getBoolean(SUCCESS)) {
        LOG.error("--- foo message ---");
        throw new Exception("message replied with error");
      }
    } catch (final Exception e) {
      LOG.error("---- bar message ---");
      throw new SvcException("failed to connect over network");
    }
  }

In the code above, I am throwing an exception with a failure message. 在上面的代码中,我抛出了带有失败消息的异常。 At the same time, I am also throwing an error on failure to connect over the network. 同时,由于无法通过网络连接,我也会引发错误。

But, if I throw an exception for !success it gets caught again, causing duplicate logging. 但是,如果我为!success抛出异常,它将再次被捕获,从而导致重复记录。 I do not want to print bar message , if I only want to log foo message . 如果我只想记录foo message ,我不想打印bar message foo message

How to prevent it from happening? 如何防止它发生?

Validate the response after the try-catch statement. try-catch语句之后验证response

JSONObject response = null;
try {
    response = /* make network call */;
} catch (final Exception e) {
    LOG.error("---- bar message ---");
    throw new SvcException("failed to connect over network");
}

if (!response.getBoolean(SUCCESS)) {
    LOG.error("--- foo message ---");
    throw new Exception("message replied with error");
}

I don't recommend catching Exception - it's too general, I suggest you narrow it down to a more specific exception type. 我不建议捕获Exception这太笼统了,建议您将其范围缩小到更具体的异常类型。

What if you move it outside the try block.. Anyway, the reason for the first try..catch is to catch any Exception from the network call. 如果将其移到try块之外,该怎么办。无论如何,第一次try..catch的原因是从网络调用中捕获任何异常。

JSONObject response = null;
try {
    response = make network call;
} catch (final Exception e) {
    LOG.error("---- bar message ---");
    throw new SvcException("failed to connect over network");
}
if (!response.getBoolean(SUCCESS)) {
    LOG.error("--- foo message ---");
    throw new Exception("message replied with error");
}

Create your own exception type and don't catch it. 创建自己的异常类型,不要捕获它。

try {
    do stuff
    if (condition) 
        throw new MyCustomException("error")
} catch (IOException e) {
    log and rethrow
}

First, let me point out a mistake in your code. 首先,让我指出您的代码中的错误。 Your method declares that it throws Exception, but it doesn't. 您的方法声明它抛出Exception,但没有。 It throws SvcException. 它引发SvcException。 So that's what the "throws" clause should say. 这就是“ throws”子句应该说的。 (You should never say "throws Exception" anyway. You should state explicitly what kind of exception it throws.) The rest of the answer depends on whether or not your vague description "make network call" throws an exception or not. (无论如何,您永远都不要说“引发异常”。您应该明确说明它引发的异常类型。)其余的答案取决于您模糊的描述“进行网络呼叫”是否引发异常。

If it doesn't, your method should look like this: 如果不是,则您的方法应如下所示:

void connectOverNetwork() throws SvcException {
  final JSONObject response = makeNetworkCall();

  if (!response.getBoolean(SUCCESS)) {
    LOG.error("--- foo message ---");
    throw new SvcException("message replied with error");
  }
}

But that's unrealistic. 但这是不现实的。 Chances are, your "make network call" code throws something like IOException. 您的“进行网络调用”代码可能会抛出类似IOException的错误。 In this case your code should look like this: 在这种情况下,您的代码应如下所示:

void connectOverNetwork() throws SvcException {
  try {
    final JSONObject response = makeNetworkCall(); // throws IOException

    if (!response.getBoolean(SUCCESS)) {
      LOG.error("--- foo message ---");
      throw new SvcException("message replied with error");
    }
  } catch (final IOException e) {
    LOG.error("--- foo message ---");
    throw new SvcException("failed to connect", e); // wrap e inside SvcException
  }
}

Notice that I wrap the caught IOException inside the SvcException. 请注意,我将捕获的IOException包装在SvcException中。 If your SvcException doesn't do that, either rewrite it so that it can, or call its initCause() method before throwing it. 如果您的SvcException不这样做,请重写它以便可以,或者在抛出它之前调用其initCause()方法。 You should always include the original exception when reThrowing a different exception. 重新抛出其他异常时,应始终包含原始异常。

Also notice that I don't bother throwing, then catching and rethrowing an IOException. 还要注意,我不用麻烦抛出,而是捕获并重新抛出IOException。 When I detect failure. 当我检测到故障时。 I just throw the exception that I need to throw. 我只是抛出需要抛出的异常。 This means I need to log the foo message in two separate places. 这意味着我需要在两个不同的地方记录foo消息。 For most things, repeating a line of code should be avoided, but for logging, this is fine. 对于大多数情况,应该避免重复执行一行代码,但是对于日志记录来说,这很好。

But this code is a bit messy. 但是这段代码有点混乱。 I would clean it up by separating the test for success from the possible IOException. 我将成功测试与可能的IOException分离开来进行清理。 So I would write it like this: 所以我会这样写:

void connectOverNetwork() throws SvcException {
  JSONObject response; // no need to initialize this.
  try {
    response = makeNetworkCall(); // throws IOException
  } catch (final IOException e) {
    LOG.error("--- foo message ---");
    throw new SvcException("failed to connect", e); // wrap e inside SvcException
  }

  if (!response.getBoolean(SUCCESS)) {
    LOG.error("--- foo message ---");
    throw new SvcException("message replied with error");
  }
}

Notice here that response is declared before the try loop. 请注意,此处的响应是在try循环之前声明的。 It's not initialized because there's no way it will reach the !response.getBoolean(SUCCESS) test without a value. 它没有被初始化,因为没有值就无法达到!response.getBoolean(SUCCESS)测试。 If makeNetworkCall() throws an exception, it won't even reach that line. 如果makeNetworkCall()引发异常,它甚至不会到达该行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM