简体   繁体   中英

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. I do not want to print bar message , if I only want to log foo message .

How to prevent it from happening?

Validate the response after the try-catch statement.

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.

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.

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. It throws SvcException. So that's what the "throws" clause should say. (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. 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. If your SvcException doesn't do that, either rewrite it so that it can, or call its initCause() method before throwing it. 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. 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. 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. 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. It's not initialized because there's no way it will reach the !response.getBoolean(SUCCESS) test without a value. If makeNetworkCall() throws an exception, it won't even reach that line.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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