Mikhail Batcer
Mikhail Batcer

Reputation: 2065

Specific and same actions when catching multiple exceptions

I want to handle exceptions of two different types differently, and after that to make some same actions for both exception types. How to do that in Java?

The following code shows what I want to do, but it is not correct, as one exception can not be caught twice.

What is the right syntax for this?

try {
    // do something...
} 
catch (ExceptionA e) {
    // actions for ExceptionA
}
catch (ExceptionB e) {
    // actions for ExceptionB
}
catch (ExceptionA | ExceptionB e) {
    // actions for ExceptionA & ExceptionB
}

Upvotes: 14

Views: 6892

Answers (5)

Mick Mnemonic
Mick Mnemonic

Reputation: 7956

Use the catch (ExceptionA | ExceptionB e) construct. Within the catch block, first do an instanceof check for e and handle the exception types separately. After this, have the common handling for both types. This way you can do everything in one catch block:

try {
    // do something...
} catch (ExceptionA | ExceptionB e) {
    if (e instanceof ExceptionA) {
        // handling for ExceptionA
    } else {
        // handling for ExceptionB
    }
    // common handling for both exception types
}

Upvotes: 10

Olimpiu POP
Olimpiu POP

Reputation: 5067

Would a solution of this type work for you:

try {
// do something...
} catch (ExceptionA | ExceptionB e) {
    // common code to be called for both...
    // ....
    handleException(e)
}

//.... 
void handleException(ExceptionA e) {
   // code for A
}
//....
void handleException(ExceptionB e) {
   // code for B
}

In this way first you do the common actions for the two issues, afterwards you have the common code for each of the exceptions in the appropriate method. In this way you don't need to use instanceof or ifs.

Another way of doing it only by using java constructs is by putting in the finally as well:

boolean fail = false;

try {
  // your code
} catch (ExceptionA a) {
   // exceptionA specific handling
   fail = true;
} catch (ExceptionB b) {
   // exceptionB specific handling
   fail = true;
} finally {
    if (fail) {
       // common handling
    }
}

Upvotes: 3

Anonymous Coward
Anonymous Coward

Reputation: 3200

Use a method for the common code.

try {
    // do something...
} 
catch (ExceptionA e) {
    // actions for ExceptionA
    doCommon(parameters);
}
catch (ExceptionB e) {
    // actions for ExceptionA
    doCommon(parameters);
}

.....

void doCommon( parameters ) {
  // actions for ExceptionA & ExceptionB
}

That will work for most things.
Though there are some exceptions like return. For that you can have doCommon return wether the caller has to return or not and use it as :

catch (ExceptionA e) {
    // actions for ExceptionA
    if ( doCommon(parameters) )
      return;
}
catch (ExceptionB e) {
    // actions for ExceptionA
    if ( doCommon(parameters) )
      return;
}

A "native Java" solution does not exist. JLS specifies (emphasis mine) :

14.20.1. Execution of try-catch

A try statement without a finally block is executed by first executing the try block. Then there is a choice:

If execution of the try block completes normally, then no further action is taken and the try statement completes normally.

If execution of the try block completes abruptly because of a throw of a value V, then there is a choice:

If the run-time type of V is assignment compatible with (§5.2) a catchable exception class of any catch clause of the try statement, then the first (leftmost) such catch clause is selected. The value V is assigned to the parameter of the selected catch clause, and the Block of that catch clause is executed, and then there is a choice:

If that block completes normally, then the try statement completes normally.

If that block completes abruptly for any reason, then the try statement completes abruptly for the same reason.

If the run-time type of V is not assignment compatible with a catchable exception class of any catch clause of the try statement, then the try statement completes abruptly because of a throw of the value V.

So only the first catch block which applies is executed. There is no way to execute two catch blocks for the same try statement.

Upvotes: 3

yas
yas

Reputation: 3620

You can rethrow the exception and handle it again:

try {
    try {
        // do something
    } catch( ExceptionA e) {
        // actions for ExceptionA
        throw e;
    } catch( ExceptionB e) {
        // actions for ExceptionB
        throw e;
    } 
} catch( ExceptionA | ExceptionB e) {
    // Actions for exceptions A or B
}

Maybe, for sake of clarity, you could refactor into methods. I'm assuming the exceptions are checked exceptions.

private void doSomethingHelper() throws ExceptionA, ExceptionB {
    try {
        // do something
     } catch( ExceptionA e) {
         // actions for ExceptionA
         throw e;
     } catch( ExceptionB e) {
         // actions for ExceptionB
         throw e;
     } 
}

public void doSomething() {
    try {
        doSomethingHelper();
    } catch( ExceptionA | ExceptionB e ) {
        // Actions for exceptions A or B
    }
}

Upvotes: 0

insidesin
insidesin

Reputation: 753

If you are seeking (ExceptionA | ExceptionB) you will be able to catch either and handle identically, only one will be required to fail. This is essentially just new (1.7) shorthand for multiple Exception conditions.

There is no such thing as catch(ExceptionA && ExceptionB).

For example:

readFile {
    try {
        open the file;
        determine its size;
        determine its content;
    } catch (fileOpenFailed) {
       doSomething;
    } catch (sizeDeterminationFailed) {
        doSomething;
    } catch (contentDeterminationFailed) {
        doSomething;
    }
}

If you wanted to catch contentDeterminationFailed and sizeDeterminationFailed as the single exception then you would want to create your own custom exception type which can be handled uniquely.

Upvotes: 1

Related Questions