En un proyecto Java actual que tenemos un código similar al siguiente ejemplo:cómo ejecutar mejor un conjunto de métodos, incluso si una excepción ocurre
try {
doSomeThing(anObject);
}
catch (SameException e) {
// Do nothing or log, but don't abort current method.
}
try {
doOtherThing(anObject);
}
catch (SameException e) {
// Do nothing or log, but don't abort current method.
}
// ... some more calls to different method ...
try {
finallyDoYetSomethingCompletelyDifferent(anObject);
}
catch (SameException e) {
// Do nothing or log, but don't abort current method.
}
Como se puede ver, varios método diferente se denominan con la exacta mismo objeto y para cada llamada se captura la misma excepción y se maneja de la misma manera (o de una manera muy similar). La excepción no se vuelve a lanzar, pero solo se puede registrar y luego descartar.
La única razón por la que hay un try-catch
alrededor de cada método, es ejecutar siempre todos los métodos, sin importar si un método ejecutado anteriormente falló.
No me gusta el código anterior. Ocupa mucho espacio, es muy repetitivo (especialmente el registro realizado en el bloque catch
, no se presenta aquí) y simplemente se ve mal.
Puedo pensar en otras formas de escribir este código, pero tampoco me gustan mucho. Las siguientes opciones vinieron a la mente:
secuencia de bucle interruptor/de-caso paradigmático
(Ver Wikipedia o The Daily WTF)
for (int i = 0; i <= 9; i++) {
try {
switch (i) {
case 0:
doSomeThing(anObject); break;
case 1:
doOtherSomeThing(anObject); break;
// ...More cases...
case 9:
doYetSomethingCompletelyDifferent(anObject); break;
}
}
catch (SameException e) {
// Do nothing or log, but don't abort current method.
}
}
Esto es obviamente mal código, muy propenso a errores y parece amateur.
Reflexión
utilizar la reflexión para llegar Method
objetos para los métodos para llamar y los almacenan en una lista en el orden en que se supone que deben ser ejecutados. Luego itere sobre esta lista y llame al método usando anObject
como único parámetro. La excepción se maneja dentro del bucle.
No me gusta este enfoque, ya que los errores (por ejemplo, los errores ortográficos en los nombres de los métodos) solo aparecen durante el tiempo de ejecución y la API de reflexión es algo hablador.
Functor
crear una clase Functor así:
private class Functor
{
void doStuff(MyObject object) throws SameException;
}
continuación, crear una lista de objetos Functor
que llaman a los métodos. De esta manera:
List<Functor> functors = new ArrayList<Functor>();
functors.add(new Functor() {
@Override
public void execute(MyObject anObject) {
doSomeThing(anObject);
}
});
functors.add(new Functor() {
@Override
public void execute(MyObject anObject) {
doOtherSomeThing(anObject);
}
});
Más tarde, recorrer esta lista y llamar execute()
en cada objeto Functor
. Puedo resumir mi sentimiento acerca de este enfoque con dos palabras: Código hinchado.
Como realmente no me gustan los cuatro enfoques, me gustaría discutir este problema aquí. ¿Cuál crees que es el mejor enfoque? ¿Cómo resolvió problemas similares en el pasado? ¿Hay quizás una solución mucho más simple que extrañé por completo?
La hinchazón es aún peor que eso: usted (y él) olvidó la cláusula throws. –
¡Guau, eres rápido! :) También pensé en cierres/delegados. Pero, como dijiste, la construcción más similar que Java tiene para ofrecer son funtores. Quizás tenga razón sobre el uso de un formato de código que es mejor para leer, pero no necesariamente respeta la guía de estilo que utilizamos. –
@mmyers En el código original, la excepción capturada es una RuntimeException. Entonces esto no es un problema en este caso particular. (En otros puede ser, por supuesto.) –