View Full Version : [JAVA] Quando si usa finally?
wingman87
09-04-2008, 09:30
Ho capito come funziona finally però non ho trovato esempi in cui il suo utilizzo sia necessario. Sul libro che sto leggendo c'è l'esempio seguente:
public void insertInDB(){
try{
cmd.executeUpdate("INSERT INTO...");
}catch(SQLException exc){
exc.printStackTrace();
}finally{
connection.close();
}
}
Ok, con questo ho capito cosa fa finally ma non avrei potuto fare la stessa cosa così?
public void insertInDB(){
try{
cmd.executeUpdate("INSERT INTO...");
}catch(SQLException exc){
exc.printStackTrace();
}
connection.close();
}
E' questo che non capisco... Grazie a chi mi illuminerà! :)
khelidan1980
09-04-2008, 09:55
no perchè in quel caso se viene sollevata l'eccezione l'esecuzione non arriva a quel punto ma viene ritornato il controllo al main,finally serve per l'appunto in caso di eccezione viene eseguito il codice compreso nel blocco finnaly prima di ritornare il controllo al main
no perchè in quel caso se viene sollevata l'eccezione l'esecuzione non arriva a quel punto ma viene ritornato il controllo al main,finally serve per l'appunto in caso di eccezione viene eseguito il codice compreso nel blocco finnaly prima di ritornare il controllo al main
No, non è vero.
class FinallyTest {
public static void main(String[] args) {
testFinally();
}
private static void testFinally() {
try {
System.out.println("Try...");
throw new Exception();
} catch (Exception ex) {
System.out.println("Catch...");
}
System.out.println("Finally...");
}
}
$> java FinallyTest
Try...
Catch...
Finally...
In questo caso può anche scrivere come ha fatto, ma è uno stile che non consiglio per diversi motivi:
Ad esempio:
1) nel mondo reale "connection.close()" lancia anch'essa una SQLException, e va gestita.
2) nell'esempio fai solo il printStackTrace dell'eccezione...se ti accontenti va pure bene...ma in realtà quello che vuoi fare è incapsulare l'eccezione in un tipo con un livello di astrazione più alto e rilanciarla. Quindi o ti gestisci la chiusura della connessione nel 'catch' (gestendo anche l'ulteriore SQLException) o usi 'finally'.
Edit: scusate l'errore semantico...ho chiamato la classe FinallyTest e ho stampato a console "finally..." e non c'è nessuna clausola 'finally'...mah! son proprio fuso!
wingman87
09-04-2008, 10:16
1) nel mondo reale "connection.close()" lancia anch'essa una SQLException, e va gestita.
2) nell'esempio fai solo il printStackTrace dell'eccezione...se ti accontenti va pure bene...ma in realtà quello che vuoi fare è incapsulare l'eccezione in un tipo con un livello di astrazione più alto e rilanciarla. Quindi o ti gestisci la chiusura della connessione nel 'catch' (gestendo anche l'ulteriore SQLException) o usi 'finally'.
1) Sì, è vero, poco più avanti nel libro aggiunge anche questa correzione, era per fare un esempio semplice.
2) Adesso ho capito e ha tutto più senso.
Grazie mille!
Il finally serve effettivamente solo quando serve "Propagare" l'eccezione all'esterno, senza la quale il codice sarebbe bruttino.
Scrivo pseudocodice:
try
{
Db.ConnectionOpen
Db.FaiqualcosaColDatabase
Db.Commit
}
Catch
{
Db.RollBack
Throw Exception all'esterno.
}
Finally
{
Db.CloseConnection
}
In questo caso p.es. io propago l'eccezione al chiamante, ma la connessione al DB sara' correttamente chiusa in tutti i casi.
khelidan1980
09-04-2008, 10:33
No, non è vero.
Già ho scritto una cavolata,son fuso pure io alle 11 di mattina mah
... il finally non serve a propagare errori ... e un concetto (secondo me e forse nn solo) sbagliato , il finally racchiude un pezzo di codice che dovra essere eseguito a prescindere dal fatto che e il codice nel try ha generato o no errori , (ad esempio si vuole chiudere una connessione sia che la transazione e andata a buon fine o meno , oppure un quando si ha aperto un socket , un file ... ) perche il finally e sempre eseguito (sempre) , anche quando c'e la clausola return nel try
try{
return;
}catch(Exception e){
}finnaly{
}
nel caso nn si voglia gestire la eccezione in "questo metodo" si puo definire un blocco composto solo di try/finally
try{
return;
}finnaly{
}
Ho capito come funziona finally però non ho trovato esempi in cui il suo utilizzo sia necessario. Sul libro che sto leggendo c'è l'esempio seguente:
public void insertInDB(){
try{
cmd.executeUpdate("INSERT INTO...");
}catch(SQLException exc){
exc.printStackTrace();
}finally{
connection.close();
}
}
Ok, con questo ho capito cosa fa finally ma non avrei potuto fare la stessa cosa così?
public void insertInDB(){
try{
cmd.executeUpdate("INSERT INTO...");
}catch(SQLException exc){
exc.printStackTrace();
}
connection.close();
}
E' questo che non capisco... Grazie a chi mi illuminerà! :)
nel primo caso la connessione verra chiusa sempre , mentre nel secondo caso solo quando il try non genera un eccezione ( in entrabi i casi dovrai cmq gestire l'eccezione generata dal metodo conection.close() )questo discorso vale nel caso tu vuoi rilanciare l'eccezione ... se no non ha molto senso il finnally xche dopo la clausola catch , il tuo programma (metodo) continuera a funzionare normalmente
... il finally non serve a propagare errori ... e un concetto (secondo me e forse nn solo) sbagliato ,
Io non ho detto che il finally serve per propagare errori.
Ho solo detto che il finally lo si usa praticamente solo quando si vogliono propagare gli errori per i quali si e' scritto il costrutto try-catch
volendo pero' ritirare correttamente le risorse.
Negli altri casi se ne puo' fare a meno, come ha anche evidenziato Shinya.
L'esempio del return in mezzo e' fuorviante. Spero che nessuno piazzi return in mezzo alle funzioni, soprattutto durante transazioni o in presenza di risorse che richiedono chiusure (file, etc.)
i o in presenza di risorse che richiedono chiusure (file, etc.)
ma cmq il finnaly viene eseguito anche se c'e il return "in mezzo" (subito prima del return ) xcio e legale dichiarare return nel try , ( ovviamente in certi casi e proprio brutto ma quando in un metodo si esegue solo codice "pericoloso" quindi tuto chiuso nel try e il catch rilancia l'eccezione ... certo nessuno vieta mettere il return alla fine del metodo anche in questo caso , ( forse dipende anche dallo stile che uno si abitua a usare )
nel caso nn si voglia gestire la eccezione in "questo metodo" si puo definire un blocco composto solo di try/finally
try{
return;
}finnaly{
}
Questa non l'ho capita. Cosa vorresti fare nel 'finally' che non puoi fare prima del 'return'?
wingman87
09-04-2008, 11:27
L'esempio del return in mezzo e' fuorviante. Spero che nessuno piazzi return in mezzo alle funzioni, soprattutto durante transazioni o in presenza di risorse che richiedono chiusure (file, etc.)
In effetti prima di postare avevo notato questa possibilità del finally, ma non ne vedevo l'utilità (non che adesso la veda), quindi ho aperto questo thread.
Vi ringrazio tutti, adesso penso di aver capito a fondo l'utilità del finally.;)
ma cmq il finnaly viene eseguito anche se c'e il return "in mezzo" (subito prima del return ) [...CUT...]
Prima del 'return' dici?
Cosa stampa questo codice allora?
class FinallyTest2 {
public static void main(String[] args) {
System.out.println(test());
}
private static boolean test() {
try {
return true;
} finally {
return false;
}
}
}
Questa non l'ho capita. Cosa vorresti fare nel 'finally' che non puoi fare prima del 'return'?
semplicemente
try{
//codice pericoloso
return qualcosa;
}finally{
// codice da eseguire anche se il try lancia un eccezione (che ovviamente sara gestita ad un livello + alto)
}
beh , il finnaly viene sempre eseguito e quindi stampera false
Edit: e cmq nn e che o inventato io il blocco try/finnaly , io ho detto solo che legale , poi dipende dalle esigenze ( quando meno te lo aspetti puo tornare utile :) )
beppegrillo
09-04-2008, 12:28
I finally lo usi per rilasciare risorse che hai acquisito, e che dovrai liberare indipendentemente dal fatto che il tuo programma ha lanciato o meno un'eccezione.
Il libro ti ha fatto l'esempio di una connessione al DB, poteva essere anche un file o qualsiasi altra cosa.
Samaritan
11-10-2014, 15:22
Il blocco finally{...} serve a garantire la sua esecuzione indipendentemente dal fatto che si generi un'eccezione.
E' quindi fondamentale in tutti i casi in cui si deve necessariamente rilasciare una risorsa come ad esempio una connessione ad un db od un Socket o più in generale uno Stream.
Tutti oggetti che sono implicitamente associati ad una connessione o ad un flusso di trasferimento dati.
Quando si ha a che fare con questo tipo di oggetti e non si usa un blocco finally, nel 99% dei casi si avrà a che fare con quel tipo di bug più difficili da individuare e che ti fanno bloccare tutto il programma senza neanche avere una eccezione che ti fa capire in modo chiaro la causa del blocco stesso.
Questo perché ogni volta che si usa un costrutto try...catch si lasciano al flusso di esecuzione automaticamente due sole strade tra loro mutuamente esclusive:
1-Va tutto correttamente, quindi il blocco del catch non viene proprio eseguito.
2-Si genera l'eccezione ed il blocco del catch viene eseguito, ma tutto il resto non viene eseguito perché il flusso viene bloccato dal catch e sale verso il chiamante.
Quindi se si decide di rilasciare una risorsa direttamente nel catch, questa sarà effettivamente rilasciata se e solo se si genera l'eccezione, ma se tutto va correttamente la risorsa non viene rilasciata!
Questo implica uno spazio occupato in memoria che rimarrà occupato e questo accadrà ogni volta che sarà rieseguito il codice che sta nel try senza che si generi alcuna eccezione.
Ecco perché il costrutto finally{} ci viene in aiuto e ci permette di rilasciare una risorsa sempre e comunque: sia che si generi un'eccezione e sia che vada tutto correttamente.
In generale si può esemplificare dicendo che il costrutto finally serve ogni qual volta si ha la necessità di eseguire un certo codice indipendentemente dal flusso di esecuzione.
Questa situazione si verifica sempre quando si ha a che fare con gli oggetti che ho citato prima e cioè con tutti quegli oggetti che sono intrinsecamente associati a flussi di dati che in quanto tali richiedono l'allocazione di buffer in memoria.
Credimi: se non si usa il finally con questo tipo di oggetti ci si garantisce ore ed ore e forse giorni di esaurimento nervoso per capire la causa di un blocco che prima o poi arriverà.
;)
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.