Come aggirare gli oggetti non inizializzati nel blocco 'finally'?

7

Mi piace usare final variabili quando possibile. Spesso queste variabili devono essere chiuse in seguito. Nota che attualmente sto lavorando su Java 6 quindi non c'è l'interfaccia closeable , ma lo stesso vale per le versioni successive di Java. Ad esempio:

final InputStream in;

try{
    in=new InputStream(...);
    //...
}catch(...) {}
finally{
    in.close(); //whoops!
}

A quel punto l'IDE farà notare che in potrebbe non essere inizializzato. Disporre l'istruzione close in un if like so

if(in!=null)
    in.close();

non funziona neanche, nonostante null sia il valore predefinito per gli oggetti non inizializzati. La mia soluzione finora è dimenticare di dichiararli final in primo luogo e inizializzarli come null alla dichiarazione.

Un'altra soluzione consiste nel posizionare la dichiarazione e l'istruzione close nel blocco try :

try{
    final InputStream in=new InputStream(...);
    //...
    in.close();
}catch(InputStreamRelatedException) {};

che lascerebbe in open (?) in caso di eccezione correlata a InputStream .

Qual è il metodo preferito?

    
posta rath 24.12.2015 - 10:56
fonte

2 risposte

14

Stai incontrando difficoltà perché stai provando a gestire due casi diversi con lo stesso try-catch:

  • costruendo il InputStream potrebbe fallire, nel qual caso non puoi neanche close() di qualcosa.
  • utilizzando InputStream potrebbe fallire, nel qual caso hai bisogno di close() .

La soluzione è separare questi casi e non creare un'istanza dell'oggetto nello stesso ambito in cui potrebbe essere utilizzato:

final InputStream in;
try { in = new InputStream(); }
catch (...) { ... /* must throw or return, or assign to 'in' */ }

try { doSomethingWith(in); }
catch (...) { ... }
finally { in.close(); }
    
risposta data 24.12.2015 - 11:20
fonte
1

Sono d'accordo con Amon che ci sono due preoccupazioni separate, ma non sono d'accordo con lui / lei su quali siano queste preoccupazioni. Scegliendo un insieme leggermente diverso di preoccupazioni puoi scrivere il codice terser. Inoltre, il blocco di codice di amon lancia un IOException perché in.close() IOException non viene catturato, ma il mio codice non dura fino a quando si cattura IOException nel blocco catch.

IMO le due preoccupazioni sono:

  • un errore I / O che si verifica in qualsiasi punto (nella costruzione o nell'uso del flusso)
  • chiusura dello stream

Con questo in mente, possiamo scrivere un codice come:

try {
  final InputStream in = ... // assign in
  try {
    // use in
  } finally {
    in.close();
  }
} catch (...) {} // if you catch IOException here, the block throws no IOException

Si noti che idealmente si metterebbe un ulteriore try / catch attorno a in.close() per fermare qualsiasi eccezione lanciata da soppiantare l'eccezione nel blocco esterno. Ma è orribilmente prolisso.

Per inciso, non usa l'anti-pattern dell'assegnazione di null a in e verifica null nel blocco finally . Complifica il codice senza una buona ragione.

    
risposta data 28.12.2015 - 17:38
fonte

Leggi altre domande sui tag