¿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?

froadie
fuente

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
OscarRyz
fuente
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();
}
usuario454322
fuente
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)
{
    ...
}
crusam
fuente
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 ) { 
  ...
}
Michael Shopsin
fuente
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.

duffymo
fuente
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.

Oleg Vaskevich
fuente
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.
  }
Bill S
fuente
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)
}
Shiva
fuente
¿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
    }
}
Dr.jacky
fuente
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.

Vineet Reynolds
fuente