2010-04-08 14 views
8

Perché Java non mi consente di assegnare un valore a una variabile finale in un blocco catch dopo aver impostato il valore nel blocco try, anche se non lo è possibile per il valore finale da scrivere in caso di eccezione.Assegnazione di un valore predefinito a una variabile finale in caso di un'eccezione in Java

Ecco un esempio che illustra il problema:

public class FooBar { 

    private final int foo; 

    private FooBar() { 
     try { 
      int x = bla(); 
      foo = x; // In case of an exception this line is never reached 
     } catch (Exception ex) { 
      foo = 0; // But the compiler complains 
        // that foo might have been initialized 
     } 
    } 

    private int bla() { // You can use any of the lines below, neither works 
     // throw new RuntimeException(); 
     return 0; 
    } 
} 

Il problema non è difficile da risolvere, ma vorrei capire perché il compilatore non accetta questo.

Grazie in anticipo per eventuali ingressi!

+2

Bene, se si sta osservando l'eccezione generale 'potrebbe essere possibile che qualcosa si verifichi solo dopo/durante' foo = x' che genererebbe un'eccezione? Forse il compilatore sta "giocando sul sicuro"? – FromCanada

+0

Bene, questa è la domanda. Ma dubito davvero che un incarico possa generare un'eccezione e scrivere ancora un valore nella variabile. – Alfonso

+2

Dove dici "In caso di un'eccezione questa linea non viene mai raggiunta" Sospetto che il compilatore rifiuti di conoscere le tue intenzioni a quel livello di granularità. Quindi tutto ciò che vede è che viene assegnato due volte. Forse la ragione è che, questo permette al compilatore di ottimizzare il codice fino a foo = bla(), dato che x è in definitiva superfluo? Sto solo speculando. – greim

risposta

7
try { 
    int x = bla(); 
    foo = x; // In case of an exception this line is never reached 
} catch (Exception ex) { 
    foo = 0; // But the compiler complains 
      // that foo might have been initialized 
} 

Il motivo è perché il compilatore non può dedurre che l'eccezione può essere lanciata solo prima foo è initalized. Questo esempio è un caso particolare in cui è evidente che questo è vero, ma prendere in considerazione:

try { 
    int x = bla(); 
    foo = x; // In case of an exception this line is never reached...or is it? 
    callAnotherFunctionThatThrowsAnException(); // Now what? 
} catch (Exception ex) { 
    foo = 0; // But the compiler complains 
      // that foo might have been initialized, 
      // and now it is correct. 
} 

Per scrivere un compilatore per gestire casi molto specifici come questo sarebbe un compito immenso - ci sono probabilmente molti di loro.

+0

Immagino che questo sia il problema qui. L'incarico deve essere il dopo ogni affermazione che può avere effetti collaterali, che immagino non sarebbe troppo difficile da controllare, ma d'altra parte non è davvero necessario in quanto si può aggirare facilmente (se un po 'brutto). – Alfonso

0

Che ne dici di un lancio Error?

+0

Giusto, prova a prendere invece Lancio. Se ti lascerà. – bmargulies

+0

Questo si propagherebbe fuori dal blocco try-catch e risulterebbe in un'eccezione al chiamante di 'new FooBar();'. Quindi la variabile finale non verrebbe mai scritta comunque. Ma nel mio caso il compilatore si lamenta che la variabile potrebbe essere scritta due volte, il che non è sicuramente il caso. – Alfonso

+0

Sì, hai ragione. Ho interpretato male la domanda. In realtà sono anche irritato da questo. – lexicore

2

Per essere un pedante, Thread.stop(Throwable) potrebbe generare un'eccezione immediatamente dopo l'assegnazione del blocco try.

Tuttavia, le regole con assegnazione definita e termini affini sono abbastanza complesse. Controlla il JLS. Cercare di aggiungere più regole complicherebbe la lingua e non fornirà un vantaggio significativo.

+0

Wow, non sapevo di Thread.stop (Throwable). Questo deve essere il metodo più malvagio nell'intero JDK ... – Alfonso

+0

+1 per menzionare il JLS. Non è solo un capriccio dell'implementazione del compilatore. – Antimony

Problemi correlati