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

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");
    }
  }

在上面的代码中,我抛出了一个带有失败消息的异常。 同时,我也报了网络连接失败的错误。

但是,如果我为 !success 抛出异常,它会再次被捕获,导致重复记录。如果我只想记录 foo message.

,我不想打印 bar message

如何预防?

验证 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");
}

我不建议捕获 Exception - 它太笼统了,我建议您将其缩小到更具体的异常类型。

如果将它移到 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");
}

创建您自己的异常类型并且不捕获它。

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

首先,让我指出您代码中的一个错误。您的方法声明它抛出异常,但它没有。它抛出 SvcException。所以这就是 "throws" 子句应该说的。 (无论如何你都不应该说 "throws Exception" 。你应该明确说明它抛出的异常类型。)其余的答案取决于你的模糊描述 "make network call" 是否抛出异常。

如果没有,您的方法应如下所示:

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

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

但这不现实。很有可能,您的 "make network call" 代码会抛出类似 IOException 的异常。在这种情况下,您的代码应如下所示:

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
  }
}

请注意,我将捕获的 IOException 包装在 SvcException 中。如果您的 SvcException 不这样做,要么重写它以便它可以,要么在抛出它之前调用它的 initCause() 方法。在重新抛出不同的异常时,您应该始终包含原始异常。

另请注意,我没有费心抛出,然后捕获并重新抛出 IOException。当我检测到故障时。我只是抛出我需要抛出的异常。这意味着我需要在两个不同的地方记录 foo 消息。对于大多数事情,应该避免重复一行代码,但是对于日志记录,这很好。

但是这段代码有点乱。我会通过将成功测试与可能的 IOException 分开来清理它。所以我会这样写:

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");
  }
}

这里注意response是在try循环之前声明的。它没有被初始化,因为没有值它无法到达 !response.getBoolean(SUCCESS) 测试。如果 makeNetworkCall() 抛出异常,它甚至不会到达该行。