ChatGPT解决这个技术问题 Extra ChatGPT

Can I catch multiple Java exceptions in the same catch clause?

In Java, I want to do something like this:

try {
    ...     
} catch (/* code to catch IllegalArgumentException, SecurityException, 
            IllegalAccessException, and NoSuchFieldException at the same time */) {
   someCode();
}

...instead of:

try {
    ...     
} catch (IllegalArgumentException e) {
    someCode();
} catch (SecurityException e) {
    someCode();
} catch (IllegalAccessException e) {
    someCode();
} catch (NoSuchFieldException e) {
    someCode();
}

Is there any way to do this?


M
M. Justin

This has been possible since Java 7. The syntax for a multi-catch block is:

try { 
  ...
} catch (IllegalArgumentException | SecurityException | IllegalAccessException |
            NoSuchFieldException e) { 
  someCode();
}

Remember, though, that if all the exceptions belong to the same class hierarchy, you can simply catch that base exception type.

Also note that you cannot catch both ExceptionA and ExceptionB in the same block if ExceptionB is inherited, either directly or indirectly, from ExceptionA. The compiler will complain:

Alternatives in a multi-catch statement cannot be related by subclassing
  Alternative ExceptionB is a subclass of alternative ExceptionA

The fix for this is to only include the ancestor exception in the exception list, as it will also catch exceptions of the descendant type.


T.T - why redefine the bitwise or (|) operator? Why not use a comma, or the operator that has a more similar meaning, the logical or (||)?
@ArtOfWarfare Maybe they thought it wouldn't matter anymore after they already had come up with the syntax for multiple bounds for generics.
XOR sign ( I ) is not the same as OR ( || ), A | B means either A or B but not both A || B means either A or B or both so as for exceptions it is either exceptionA or exceptionB but not both at the same time. this is why they used XOR sing instead of OR and you can see that clearly when the exception is throws if you put 2 exceptions one of them is sub type of another
@user1512999 in Java, bitwise XOR is ^ (caret) and bitwise OR is | (pipe) docs.oracle.com/javase/tutorial/java/nutsandbolts/op3.html
It's worth mentioning that the type of an exception caught in multi-catch block is evalueted to the most derived common parent
u
user454322

Not exactly before Java 7 but, I would do something like this:

Java 6 and before

try {
  //.....
} catch (Exception exc) {
  if (exc instanceof IllegalArgumentException || exc instanceof SecurityException || 
     exc instanceof IllegalAccessException || exc instanceof NoSuchFieldException ) {

     someCode();

  } else if (exc instanceof RuntimeException) {
     throw (RuntimeException) exc;     

  } else {
    throw new RuntimeException(exc);
  }

}

Java 7

try {
  //.....
} catch ( IllegalArgumentException | SecurityException |
         IllegalAccessException |NoSuchFieldException exc) {
  someCode();
}

Note that your Java 6 example breaks the compiler's ability to tell what will be thrown from where.
@MichaelBlume True, which is not [ so ] bad. You can always get the original exception with exc.getCause(). As a side note, Robert C. Martin (among others) recommends to use unchecked exceptions (the compiler has no idea of what kind of exception will be thrown from there); refer to Chapter 7: Error Handling on his book Clean code.
In your Java 6 example shouldn't you be rethrowing the original exception instead of creating a new exception instance, i.e. throw exc instead of throw new RuntimeException(exc)?
This is pretty bad practice, from the perspective of readability.
Instanceof operation is bit costly, it's better to avoid as much as possible.
r
rob

Within Java 7 you can define multiple catch clauses like:

catch (IllegalArgumentException | SecurityException e)
{
    ...
}

d
duffymo

No, one per customer prior to Java 7.

You can catch a superclass, like java.lang.Exception, as long as you take the same action in all cases.

try {
    // some code
} catch(Exception e) { //All exceptions are caught here as all are inheriting java.lang.Exception
    e.printStackTrace();
}

But that might not be the best practice. You should only catch an exception when you have a strategy for actually handling it - and logging and rethrowing is not "handling it". If you don't have a corrective action, better to add it to the method signature and let it bubble up to someone that can handle the situation.

With JDK 7 and later you can do this:

try {
    ...     
} catch (IllegalArgumentException | SecurityException | IllegalAccessException | NoSuchFieldException e) {
    someCode();
}

Can I petition you to rephrase the portion about catching java.lang.Exception? I realize that it's an example, but I feel like some people might read this answer and say, "oh, okay, I'll just catch Exception then", when that's probably not what they want to (or should) do.
I knew about that, but I don't want to do it... Oh, well, guess I'm stuck with 4 catches then, till the next version of Java...
@duffymo: What's wrong with logging and rethrowing? Except that it clutters the code, its equivalent to not catching it, isn't it. Seen from the general error-handling strategy perspective. What's bad is logging and not rethrowing.
I don't consider logging and rethrowing handling anything. I'd prefer to let it bubble up to someone who can do something meaningful. That last layer where exceptions should never escape (e.g. controllers in a web app) should be the one to log the error in that case.
Am I the only one who finds it absurd that a log isn't automatically generated for me? It seems that we all have to write the same stupid logging message every time some piece of code might throw an exception.
A
Albert Rothman

If there is a hierarchy of exceptions you can use the base class to catch all subclasses of exceptions. In the degenerate case you can catch all Java exceptions with:

try {
   ...
} catch (Exception e) {
   someCode();
}

In a more common case if RepositoryException is the the base class and PathNotFoundException is a derived class then:

try {
   ...
} catch (RepositoryException re) {
   someCode();
} catch (Exception e) {
   someCode();
}

The above code will catch RepositoryException and PathNotFoundException for one kind of exception handling and all other exceptions are lumped together. Since Java 7, as per @OscarRyz's answer above:

try { 
  ...
} catch( IOException | SQLException ex ) { 
  ...
}

BTW catch clauses are handled in order so if you put a parent exception class before a child class then it's never called eg: try { ... } catch (Exception e) { someCode(); } catch (RepositoryException re) { // never reached }
Actually precisely because it can never be reached, such code doesn't even compile.
O
Oleg Vaskevich

A cleaner (but less verbose, and perhaps not as preferred) alternative to user454322's answer on Java 6 (i.e., Android) would be to catch all Exceptions and re-throw RuntimeExceptions. This wouldn't work if you're planning on catching other types of exceptions further up the stack (unless you also re-throw them), but will effectively catch all checked exceptions.

For instance:

try {
    // CODE THAT THROWS EXCEPTION
} catch (Exception e) {
    if (e instanceof RuntimeException) {
        // this exception was not expected, so re-throw it
        throw e;
    } else {
        // YOUR CODE FOR ALL CHECKED EXCEPTIONS
    } 
}

That being said, for verbosity, it might be best to set a boolean or some other variable and based on that execute some code after the try-catch block.


This approach prevents the compiler from determining whether or not a "catch block" will be reachable.
B
Bill S

In pre-7 how about:

  Boolean   caught = true;
  Exception e;
  try {
     ...
     caught = false;
  } catch (TransformerException te) {
     e = te;
  } catch (SocketException se) {
     e = se;
  } catch (IOException ie) {
     e = ie;
  }
  if (caught) {
     someCode(); // You can reference Exception e here.
  }

wuold be a nice solution. How about to insert the final control of caught in a finally block?
This requires more lines than the original question.
H
Hardik Shah

It is very simple:

try { 
  // Your code here.
} catch (IllegalArgumentException | SecurityException | IllegalAccessException |
            NoSuchFieldException e) { 
  // Handle exception here.
}

D
Dr.jacky

For kotlin, it's not possible for now but they've considered to add it: Source
But for now, just a little trick:

try {
    // code
} catch(ex:Exception) {
    when(ex) {
        is SomeException,
        is AnotherException -> {
            // handle
        }
        else -> throw ex
    }
}

C
Community

Catch the exception that happens to be a parent class in the exception hierarchy. This is of course, bad practice. In your case, the common parent exception happens to be the Exception class, and catching any exception that is an instance of Exception, is indeed bad practice - exceptions like NullPointerException are usually programming errors and should usually be resolved by checking for null values.