5

Tengo un bloque try/finally. Necesito ejecutar varios métodos en el bloque finally. Sin embargo, cada uno de esos métodos puede arrojar una excepción. ¿Hay alguna forma de garantizar que todos estos métodos se invoquen (o intenten) sin bloques finalmente anidados?En Java, ¿hay alguna forma de garantizar que se invoquen varios métodos en un bloque finally?

Esto es lo que hago en este momento, que es bastante feo:

protected void verifyTable() throws IOException { 
    Configuration configuration = HBaseConfiguration.create(); 
    HTable hTable = null;            

    try { 
     hTable = new HTable(configuration, segmentMatchTableName);  

     //... 
     //various business logic here 
     //... 

    } finally {       
     try { 
      try { 
       if(hTable!=null) { 
        hTable.close(); //This can throw an IOException 
       }    
      } finally { 
       try { 
        generalTableHelper.deleteTable(configuration, segmentMatchTableName); //This can throw an IOException 
       } finally { 
        try { 
         generalTableHelper.deleteTable(configuration, wordMatchTableName); //This can throw an IOException 
        } finally { 
         generalTableHelper.deleteTable(configuration, haplotypeTableName); //This can throw an IOException  
        } 
       } 
      }        
     } finally { 
      HConnectionManager.deleteConnection(configuration, true); //This can throw an IOException 
     } 
    }    
} 

¿Hay una manera más elegante de hacer esto?

+3

Puede extraerlos en un método de limpieza. – Reimeus

+0

'¿Hay alguna forma de garantizar que todos estos métodos se invoquen (o intenten) ** sin bloques finalmente anidados??' –

Respuesta

2

La manera estándar (de trabajo) para la gestión de recursos justo en Java (el principio se aplica a otros idiomas también) es:

Resource resource = acquire(resource); 
try { 
    use(resource); 
} finally { 
    resource.release(); 
} 

O mediante el acceso directo (con un poco más de inteligencia) en la corriente versión de Java sE:

try (Resource resource = acquire(resource)) { 
    use(resource); 
} 

(como Joe K señala, puede ser necesario para envolver el recurso para que sea confirmar a la interfaz específica que el lenguaje Java depende.)

dos recursos, y que acaba de aplicar el lenguaje dos veces:

Resource resource = acquire(resource); 
try { 
    SubResource sub = resource.acquire(); 
    try { 
     use(sub); 
    } finally { 
     sub.release(); 
    } 
} finally { 
    resource.release(); 
} 

Y en Java SE 7:

try (
    Resource resource = acquire(resource); 
    SubResource sub = resource.acquire() 
) { 
    use(resource, sub); 
} 

La realidad gran ventaja de la nueva característica del lenguaje es que el manejo de los recursos fue la mayoría de las veces se rompe cuando se escribe.

Es posible que tenga un manejo de excepciones más complicado. Por ejemplo, no desea enviar excepciones de bajo nivel como IOException a la aplicación propiamente dicha; es probable que desee incluir algún subtipo de RuntimeException. Esto puede, con la verboseness típica de Java, ser factorizado utilizando la expresión Execute Around (ver this excellent question). Desde Java SE 8, también habrá una sintaxis más corta con semántica aleatoriamente diferente.

with(new ResourceSubAction() { public void use(Resource resource, SubResource sub) { 
    ... use resource, sub ... 
}}); 
0

En general, no hay forma de salir de esto. Necesitas múltiples bloques finalmente.

Sin embargo, no quiero comentar su código específico, ya sea que se trate de un diseño apropiado o no. Ciertamente se ve bastante extraño.

+0

Sí, el código tiene más sentido si puede ver la lógica comercial. Lo dejé en aras de la brevedad. – sangfroid

0

No hay manera de que tenga miedo. Hubo un patrón similar al cerrar io recursos. Por ejemplo, ¿qué haces al cerrar un archivo arroja una IOException? Por lo general, solo debes ignorarlo. Como esto fue un poco si se trataba de un patrón anti, introdujeron la sintaxis try-with en Java 7. Para su ejemplo, creo que no hay otra opción. Quizás poner cada uno finalmente en su propio método para hacerlo más claro

0

Para llamar a múltiples métodos desde un bloque finally, debe asegurarse de que ninguno de ellos arroje, lo cual es una buena idea de todos modos, porque cualquier excepción arrojada desde un bloque anulará la excepción o el valor devuelto arrojado desde el try/catch.

El caso de uso más común es un archivo o conexión de base de datos, en cuyo caso se escribe un método "cerrar en silencio" (o usar uno de una biblioteca existente, como Jakarta Commons IO). Si las cosas que necesita limpiar no le permiten usar un método preexistente, escriba el suyo (en su caso, deleteTableQuietly()).

Si está utilizando JDK-7, también puede usar el constructo "try with resource".

2

Si se trata de Java 7, podría considerar usar la nueva construcción try-with-resources. Es posible que deba crear algunos contenedores AutoCloseable básicos para eliminar las tablas.

0

Puede crear una clase abstracta Acción con un método de ejecución, y derivar de esa clase una clase para cada método lanzando la excepción que desea llamar, llamando a este método desde el método de ejecución. Luego puede crear una lista de Acciones y recorrer los elementos de la lista, llamando a su método de ejecución en un bloque try finally, ignorando las excepciones.

0
deleteTableSilently(table1);  
deleteTableSilently(table2);  
deleteTableSilently(table3); 


deleteTableSilently() 
    try 
     deleteTable() 
    catch whatever 
     log.error(); 
0

considerar el uso del marco java.util.concurrent - si el código de cada llamada como una persona que se puede llamar (con nombre o anónimo), se puede usar ExecutorService.invokeAll.

Cuestiones relacionadas