¿Puedo atrapar múltiples excepciones Java en la misma cláusula catch?


699

En Java, quiero hacer algo como esto:

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

...en vez de:

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

¿Hay alguna forma de hacer esto?

Respuestas:


1131

Esto ha sido posible desde Java 7 . La sintaxis para un bloque de captura múltiple es:

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

Sin embargo, recuerde que si todas las excepciones pertenecen a la misma jerarquía de clases, simplemente puede capturar ese tipo de excepción base.

También tenga en cuenta que no puede capturar ExceptionA y ExceptionB en el mismo bloque si ExceptionB se hereda, directa o indirectamente, de ExceptionA. El compilador se quejará:

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

81
TT: ¿por qué redefinir el operador bitwise or( |)? ¿Por qué no usar una coma o el operador que tiene un significado más similar, el logical or( ||)?
ArtOfWarfare

11
@ArtOfWarfare Tal vez pensaron que ya no importaría después de que se les ocurrió la sintaxis para múltiples límites para los genéricos.
JimmyB

12
El signo XOR (I) no es lo mismo que OR (||), A | B significa A o B pero no ambos A || B significa A o B o ambos, por lo que para excepciones es una excepción A o una excepción B pero no ambas al mismo tiempo. esta es la razón por la que usaron XOR sing en lugar de OR y se puede ver claramente cuando se lanza la excepción si pones 2 excepciones, una de ellas es un subtipo de otra
user1512999

41
@ user1512999 en Java, XOR bit a bit es ^ (caret) y OR bit a bit es | (pipe) docs.oracle.com/javase/tutorial/java/nutsandbolts/op3.html
Lewis Baumstark

66
Vale la pena mencionar que el tipo de excepción atrapada en el bloque de captura múltiple se evalúa al padre común más derivado
yanpas

104

No exactamente antes de Java 7, pero haría algo como esto:

Java 6 y antes

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

11
Tenga en cuenta que su ejemplo de Java 6 rompe la capacidad del compilador de saber qué se lanzará desde dónde.
MichaelBlume

2
@MichaelBlume True, que no es [tan] malo. Siempre puede obtener la excepción original con exc.getCause(). Como nota al margen, Robert C. Martin (entre otros) recomienda utilizar excepciones no verificadas (el compilador no tiene idea de qué tipo de excepción se lanzará desde allí); consulte el Capítulo 7: Manejo de errores en su libro Código limpio .
user454322

44
En su ejemplo de Java 6, ¿no debería volver a lanzar la excepción original en lugar de crear una nueva instancia de excepción, es decir, en throw exclugar de throw new RuntimeException(exc)?
David DeMar

55
Esta es una práctica bastante mala, desde la perspectiva de la legibilidad.
Rajesh J Advani

3
La instancia de operación es un poco costosa, es mejor evitar tanto como sea posible.
Paramesh Korrakuti

23

Dentro de Java 7 puede definir múltiples cláusulas catch como:

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

16

Si hay una jerarquía de excepciones, puede usar la clase base para capturar todas las subclases de excepciones. En el caso degenerado, puede capturar todas las excepciones de Java con:

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

En un caso más común, si RepositoryException es la clase base y PathNotFoundException es una clase derivada, entonces:

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

El código anterior capturará RepositoryException y PathNotFoundException para un tipo de manejo de excepciones y todas las demás excepciones se agrupan. Desde Java 7, según la respuesta de @ OscarRyz anterior:

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

77
Por cierto, las cláusulas catch se manejan en orden, por lo que si coloca una clase de excepción principal antes de una clase secundaria, nunca se llama, por ejemplo: try {...} catch (Exception e) {someCode (); } Catch (RepositoryException re) {// nunca se ejecuta}
Michael Shopsin

44
En realidad, precisamente porque nunca se puede alcanzar, ese código ni siquiera se compila.
polygenelubricants

15

No, uno por cliente.

Puede capturar una superclase, como java.lang.Exception, siempre que realice la misma acción en todos los casos.

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

Pero esa podría no ser la mejor práctica. Solo debe detectar una excepción cuando tiene una estrategia para manejarlo realmente, y registrar y volver a lanzar no es "manejarlo". Si no tiene una acción correctiva, es mejor agregarla a la firma del método y dejar que brote a alguien que pueda manejar la situación.


20
¿Puedo pedirle que reformule la parte sobre la captura de java.lang.Exception? Me doy cuenta de que es un ejemplo, pero siento que algunas personas podrían leer esta respuesta y decir, "oh, está bien, entonces atraparé Exception", cuando eso probablemente no sea lo que quieren (o deberían) hacer.
Rob Hruska

2
Sabía eso, pero no quiero hacerlo ... Oh, bueno, supongo que estoy atrapado con 4 capturas hasta la próxima versión de Java ...
froadie

@duffymo: ¿Qué hay de malo en registrar y volver a lanzar? Excepto que satura el código, es equivalente a no atraparlo, ¿no es así? Visto desde la perspectiva de la estrategia general de manejo de errores. Lo malo es iniciar sesión y no volver a lanzar.
Frank Osterfeld

55
No considero iniciar sesión y volver a lanzar nada. Prefiero dejar que le caiga encima a alguien que pueda hacer algo significativo. La última capa donde las excepciones nunca deberían escapar (por ejemplo, los controladores en una aplicación web) debería ser la que registre el error en ese caso.
duffymo

¿Soy el único que considera absurdo que no se genere un registro automáticamente para mí? Parece que todos tenemos que escribir el mismo estúpido mensaje de registro cada vez que un fragmento de código puede generar una excepción.
ArtOfWarfare

10

Una alternativa más limpia (pero menos detallada, y tal vez no tan preferida) a la respuesta del usuario 454322 en Java 6 (es decir, Android) sería capturar todos Exceptionlos correos electrónicos y volver a lanzarlos RuntimeException. Esto no funcionaría si planea capturar otros tipos de excepciones más arriba en la pila (a menos que también las vuelva a lanzar), pero efectivamente capturará todas las excepciones marcadas .

Por ejemplo:

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

Dicho esto, para verbosidad, podría ser mejor establecer una variable booleana o alguna otra y, en función de eso, ejecutar algún código después del bloque try-catch.


1
Este enfoque evita que el compilador determine si un "bloque de captura" será accesible o no.
the_new_mr

3

En pre-7, ¿qué tal:

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

3
Sería una buena solución. ¿Qué tal insertar el control final de caughten un finallybloque?
Andrea_86

Esto requiere más líneas que la pregunta original.
Leandro Glossman

1

Si. Aquí está la forma de usar el separador de tubería (|),

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

¿Qué es este estilo de código? ¿El bloqueo en un bloque de prueba?
Sam

1

Para kotlin, no es posible por ahora, pero han considerado agregarlo: Fuente
Pero por ahora, solo un pequeño truco:

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

0

Capture la excepción que resulta ser una clase principal en la jerarquía de excepciones. Esto es, por supuesto, una mala práctica . En su caso, la excepción principal común es la clase Excepción, y capturar cualquier excepción que sea una instancia de Excepción es, de hecho, una mala práctica: las excepciones como NullPointerException suelen ser errores de programación y, por lo general, deben resolverse comprobando valores nulos.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.