2010-04-08 9 views
8

¿Por qué Java no me deja asignar un valor a una variable final en un bloque catch después de establecer el valor en el bloque try, incluso si no es posible para que se escriba el valor final en caso de una excepción.Asignación de un valor predeterminado a una variable final en caso de una excepción en Java

Aquí es un ejemplo que muestra el 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; 
    } 
} 

El problema no es difícil de evitar, pero me gustaría entender por qué el compilador no acepta esto.

¡Gracias de antemano por cualquier entrada!

+2

Bueno, si está captando la 'Excepción' general, ¿podría ocurrir algo después/durante 'foo = x' que arrojaría una excepción? ¿Tal vez el compilador está "jugando a lo seguro"? – FromCanada

+0

Bueno, esa es la pregunta. Pero realmente dudo que una tarea pueda dar como resultado una excepción lanzada y todavía escribir un valor a la variable. – Alfonso

+2

Donde dices "En caso de una excepción, esta línea nunca se alcanza" Sospecho que el compilador se niega a conocer tus intenciones hasta ese nivel de granularidad. Entonces todo lo que ve es que se le asigne dos veces. Quizás la razón es que esto permite al compilador optimizar el código para foo = bla(), ya que x es finalmente superfluo. Solo especulando. – greim

Respuesta

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 
} 

La razón es porque el compilador no puede deducir que la excepción sólo puede ser lanzado antes de foo se initalized. Este ejemplo es un caso especial de que es obvio que eso es cierto, pero hay que considerar:

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

Para escribir un compilador para manejar casos muy específicos como esta sería una tarea inmensa - hay probablemente muchos de ellos.

+0

Supongo que ese es el problema aquí. La tarea debe ser después de cualquier declaración que pueda tener efectos secundarios, que supongo que no sería muy difícil de verificar, pero, por otro lado, no es realmente necesario ya que puedes evitarla fácilmente (si es un poco feo). – Alfonso

0

¿Qué tal una lanzada Error?

+0

Correcto, intenta atrapar a Throwable en su lugar. Si te lo permite. – bmargulies

+0

Esto se propagaría fuera del bloque try-catch y daría lugar a una excepción en la persona que llama de 'new FooBar();'. Entonces la variable final nunca se escribiría de todos modos. Pero en mi caso, el compilador se queja de que la variable podría escribirse dos veces, lo que seguramente no es el caso. – Alfonso

+0

Sí, tienes razón. He malinterpretado la pregunta. En realidad, también estoy irritado por esto. – lexicore

2

Para ser un pedante, Thread.stop(Throwable) podría arrojar una excepción inmediatamente después de la asignación del bloque try.

Sin embargo, las reglas con asignación definida y términos afines son lo suficientemente complejas. Compruebe el JLS. Tratar de agregar más reglas complicaría el lenguaje y no proporcionaría un beneficio significativo.

+0

Guau, no sabía sobre Thread.stop (Throwable). Este debe ser el método más malo en todo el JDK ... – Alfonso

+0

+1 por mencionar el JLS. No es solo una peculiaridad de la implementación del compilador. – Antimony

Cuestiones relacionadas