5

Quindi ho un blocco try/finally. Ho bisogno di eseguire una serie di metodi nel blocco finally. Tuttavia, ognuno di questi metodi può generare un'eccezione. C'è un modo per garantire che tutti questi metodi siano chiamati (o tentati) senza blocchi nidificati finalmente?In java, esiste un modo per garantire che più metodi vengano richiamati in un blocco finale?

Questo è quello che faccio in questo momento, che è abbastanza brutto:

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

C'è un modo più elegante, per fare questo?

+3

È possibile estrarli in un metodo di pulizia. – Reimeus

+0

'C'è un modo per garantire che tutti questi metodi siano chiamati (o tentati) ** senza blocchi finalmente nidificati **?' –

risposta

2

L'(di lavoro) metodo standard per la gestione delle risorse a destra in Java (il principio si applica ad altre lingue come pure) è:

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

oppure usando la scorciatoia (con un po 'più di intelligenza) nella corrente versione di Java SE:

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

(come Joe K fa notare, potrebbe essere necessario per avvolgere la risorsa per renderlo confermare l'interfaccia specifica che il linguaggio Java dipende.)

due risorse, e basta applicare l'idioma due volte:

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

E in Java SE 7:

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

Il veramente grande vantaggio della nuova caratteristica del linguaggio è che la gestione delle risorse è stato più spesso che non rotto quando scritto.

È possibile avere una gestione delle eccezioni più complessa. Ad esempio, non si desidera generare eccezioni di basso livello come IOException tramite l'applicazione appropriata: è probabile che si desideri racchiudere il sottotipo RuntimeException. Questo può, con il linguaggio tipico di Java, essere scomposto usando l'idioma di Execute Around (vedi this excellent question). Da Java SE 8, ci sarà anche una sintassi più breve con semantica casualmente diversa.

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

In generale, non c'è modo di uscire da questo. Hai bisogno di più blocchi alla fine.

Tuttavia, non desidero commentare il codice specifico, indipendentemente dal fatto che sia un progetto appropriato. Certamente sembra piuttosto strano.

+0

Sì, il codice ha più senso se si può vedere la logica di business. L'ho lasciato fuori per brevità. – sangfroid

0

Non c'è modo che abbia paura. C'era un modello simile quando si chiudevano le risorse. Ad esempio, cosa fai quando chiudi un file genera una IOException? Di solito dovevi semplicemente ignorarlo. Dato che questo è un po 'se un pattern anti ha introdotto la sintassi try-in in Java 7. Per il tuo esempio penso che non ci sia altra opzione. Forse metti ciascuno finalmente nel suo metodo per renderlo più chiaro

0

Per chiamare più metodi da un blocco finally, devi assicurarti che nessuno di loro passi - che è comunque una buona idea, perché ogni eccezione lanciata da un il blocco sostituirà l'eccezione o il valore restituito generato da try/catch.

Il caso di utilizzo più comune è una connessione file o database, nel qual caso si scrive un metodo "close quietly" (o si utilizza uno da una libreria esistente, come Jakarta Commons IO). Se le cose che devi pulire non ti permettono di usare un metodo preesistente, scrivi il tuo (nel tuo caso, deleteTableQuietly()).

Se si utilizza JDK-7, è anche possibile utilizzare il costrutto "try with resource".

2

Se si tratta di Java 7, è possibile prendere in considerazione l'utilizzo del nuovo costrutto try-with-resources. Potrebbe essere necessario creare alcuni wrapper AutoCloseable di base per l'eliminazione delle tabelle.

0

È possibile creare una classe astratta Action con un metodo execute e derivare da quella classe uno per ogni metodo che genera l'eccezione che si desidera chiamare, chiamando questo metodo dal metodo execute. Quindi puoi creare un elenco di azioni e scorrere gli elementi dell'elenco, chiamando il loro metodo di esecuzione in un blocco try finally, ignorando le eccezioni.

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


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

considerare l'uso del framework java.util.concurrent - se si codifica ogni chiamata come un individuo Callable (anonimo o personale), è possibile utilizzare ExecutorService.invokeAll.