2012-02-19 18 views
14

Ho una variabile che non dovrebbe cambiare il suo valore dopo che è stata inizializzata, quindi voglio definirla come variabile finale.java: come dichiarare una variabile finale che è inizializzata all'interno di un blocco try-catch?

il problema è che la variabile deve essere inizializzato all'interno di un blocco try, quindi ottenere i seguenti problemi:

ho il seguente codice:

Connection conn = null; 
try { 
    conn = getConn(prefix); 
    [...do some stuff with conn...] 
} catch (Exception e) { 
    throw new DbHelperException("error opening connection", e); 
} finally { 
    closeConnection(conn); 
} 

Se io dichiaro la variabale come finale , senza inizializzarlo su null, ottengo un 'La variabile locale conn potrebbe non essere stata inizializzata' sul blocco finally. D'altra parte, se lo dichiaro definitivo e lo inizializzo a null, ottengo l'errore "La variabile locale finale conn non può essere assegnata" nel blocco try.

EDIT: dopo la risposta LXX, sono venuto con questa versione

try { 
    final Connection conn = conn = getConn(prefix); 
    try { 
     return selectAll(conn, sql, params); 
    } catch (Exception e) { 
     throw new DbHelperException("error executing query", e); 
    } finally { 
     closeConnection(conn); 
    } 
} catch (Exception e) { 
    throw new DbHelperException("error opening connection", e); 
} 

Quindi questo dovrebbe essere il modo per farlo?

-

Lezione imparata:

Penso che la risposta corretta alla domanda è quella che LXX ha dato, ma in questo caso penso che i contro di dichiarare le outweights finali variabili suoi benefici ...

-

EDIT: trovato due domande sul overflow dello stack su quando usare finale

When should one use final for method parameters and local variables?

Using "final" modifier whenever applicable in java

+0

Che ne dici di accodamento 'finalConnection finalConn = conn;' al tuo codice? – biziclop

+0

Perché hai bisogno sia di 'try's? Perché non avere un solo try-catch in cui ottieni la connessione e usala per selezionare tutto? – yshavit

+0

Mi chiedo perché pensi che sia così importante dichiararlo definitivo. Sembra piuttosto nannyish e naggy per me. Se fossi un utente, e ho chiamato il tuo metodo per ottenere una connessione, non riesco a vedere alcun motivo per cui vorrei mandarlo in fumo cambiandolo. E se lo facessi, direi che le conseguenze dovrebbero essere sull'utente. – duffymo

risposta

7

Si potrebbe gestire le eccezioni in modo più accurato. Se ottieni un'eccezione che apre la connessione, non devi chiuderla nel blocco finally, immagino. Se ottieni un'eccezione dopo, nel blocco try e gestisci l'eccezione in un nuovo blocco try-catch nidificato, non devi definire la variabile all'esterno. Qualcosa di simile:

try { 
     final Connection conn = getConn(prefix); 
     try { 
      //code using conn 
     } catch (Exception e) { 

     } finally { 
      closeConnection(conn); 
     } 
    } catch (DbHelperException e) { 
     throw new DbHelperException("error opening connection", e); 
    } 
+3

+1, questa è probabilmente la soluzione più pulita. – biziclop

+0

Sì, capisco cosa intendi, presumo che se c'è un'eccezione che apre la connessione, la connessione non può essere aperta, quindi non c'è bisogno di chiuderla. Sono arrivato con un'altra versione del codice, grazie alla tua risposta, controlla di nuovo la domanda ... – opensas

+0

@opensas Se c'è un'eccezione nella chiamata 'getConn()', se la connessione è stata effettivamente aperta o meno, 'conn' sarà sicuramente nullo, quindi non sarai in grado di chiuderlo comunque. – biziclop

-2

Puoi provare assegnandolo sia nella cattura e infine blocchi? Come così:

Connection connTemp = null; 
final Connection conn; 
try { 
    connTemp = getConn(prefix); 
} catch (Exception e) { 
    throw new DbHelperException("error opening connection", e); 
} finally { 
    closeConnection(conn); 
} 
conn = connTemp; 
+0

una volta dichiarato come finale non può essere modificato da nessuna parte, questo è lo scopo –

+0

Aggiornato per utilizzare una variabile temporanea. – AlexanderZ

-1

Perché lo vuoi finale? Se si desidera passare a una classe interna anonima, si potrebbe fare:

Connection conn = null; 
try { 
    conn = getConn(prefix); 
    final Connection finalConn = conn; 
    // pass it to inner class here 
} catch (Exception e) { 
    throw new DbHelperException("error opening connection", e); 
} finally { 
    closeConnection(conn); 
} 

L'unico problema (e piuttosto un grande uno) con questa soluzione è che si chiude la connessione non appena si lascia questo blocco. Quindi, a meno che tu dichiari e chiami immediatamente la tua classe interiore, questo schema non funzionerà.

In entrambi i casi, probabilmente riformulare l'intera faccenda se fossi in te, rendendo invece la finale prefix e delegando la gestione della connessione alla classe anon interna.

+0

oops! hai ragione, (a proposito, hai notato un brutto bug, grazie) - ho aggiornato la domanda ... – opensas

+2

e voglio definirla definitiva, giusto per dire al compilatore che la variabile conn non dovrebbe cambiare il suo valore dopo essere stata inizializzata ... – opensas

2

Che ne dici di questo?

Connection temp = null; 
try { 
    temp = getConn(prefix); 
} catch (Exception e) { 
    throw new DbHelperException("error opening connection", e); 
} finally { 
    closeConnection(conn); 
} 
final Connection conn = temp; 
+0

Puoi anche andare avanti e impostare il ritorno a 'null' in questo modo non lo usi più. – Michael

+4

Questo è un buon modo per ottenere un riferimento 'finale' a una connessione che è già chiusa. :) – biziclop

+1

@Michael ha permesso alla JVM di gestirlo. –

Problemi correlati