Pregunta

Yo estaba tratando de llegar a los casos de prueba oscuros para una máquina virtual Java de código abierto alternativa estoy ayudando con ( aviar ) cuando me encontré con un poco interesante de código, y me sorprendió que no se compila:

public class Test {
    public static int test1() {
        int a;
        try {
            a = 1;
            return a; // this is fine
        } finally {
            return a; // uninitialized value error here
        }
    }
    public static void main(String[] args) {
        int a = test1();
    }
}

La ruta de código más obvia (el único que veo) es ejecutar a = 1, "intento" para devolver una (la primera vez), luego ejecutar el último, que realmente retornos a. Sin embargo, javac se queja de que "a" puede que no se han inicializado:

    Test.java:8: variable a might not have been initialized  
        return a;  
               ^  

Lo único que se me ocurre que podría causar / permitir que una ruta de código diferente es si una excepción de tiempo de ejecución oscura se produjera después del inicio de la prueba pero antes de que el valor 1 se asigna a una - algo parecido a un OutOfMemoryError o un StackOverflowException, pero no puedo pensar en cualquier caso en que éstos posiblemente podrían ocurrir en este lugar en el código.

Puede alguien más familiarizados con los detalles del estándar de Java arrojar alguna luz sobre esto? Se trata sólo de un caso en que el compilador está siendo conservadora - y por lo tanto se niega a elaborar lo que sería un código válido? - o es algo extraño pasando aquí

¿Fue útil?

Solución

Puede parecer contra intuitivo que una excepción podría ocurrir en el a = 1 línea, pero podría producirse un error de JVM. Por lo tanto, dejando la variable a inicializar. Por lo tanto, el error del compilador tiene sentido completo. Esto es que error de ejecución oscura que usted ha mencionado. Sin embargo, yo diría que un OutOfMemoryError está lejos de ser oscura y debe ser, al menos, pensó por los desarrolladores. Además, hay que recordar que el estado que establece el OutOfMemoryError podría ocurrir en otro hilo y la única acción que empuja la cantidad de memoria de almacenamiento dinámico utilizado más allá del límite es la asignación de la variable a.

De todas formas, ya que usted está buscando en el diseño de compiladores, también estoy asumiendo que ya sabe lo tonto que es para devolver valores en un bloque finally.

Otros consejos

La especificación del lenguaje Java requiere que se le asigna una variable antes de ser usado. El JLS define normas específicas para la que se conoce como las reglas "Asignación definido". Todos los compiladores Java necesidad de adherirse a ellos.

JLS 16.2.15 :

  

V se asignaron claramente antes de que el bloque finally si y sólo si V se asignaron claramente antes de la sentencia try.

En otras palabras, cuando se considera la sentencia finally, las instrucciones de bloque try y catch dentro de una declaración asignaciones try-catch-finally no se consideran.

No es necesario decir, que la especificación está siendo muy conservadora aquí, pero preferiría tener la especificación sea simple aunque un poco limitado (creen que las reglas son ya complicada) que sea indulgente pero difícil de entender y razonar acerca de.

Los compiladores tienen que seguir estas reglas de asignación definida, por lo que todos los compiladores emiten los mismos errores. Los compiladores no están autorizados a realizar cualquier análisis adicional que el JLS especifica para suprimir cualquier error.

Creo que es sólo debido a la semántica de una relación try-catch-finally. Desde el rel="nofollow de Java Language Specification :

  

Si la ejecución del bloque try   se completa con normalidad, entonces el fin   se ejecuta el bloque ...

     

Si la ejecución del bloque try   completa bruscamente a causa de un tiro   de un valor de V ...

     

Si la ejecución del bloque try   completa bruscamente por cualquier otra   R razón, entonces el bloque finally es   ejecutado ...

El último caso parece ser el más relevante aquí. Parece que finalmente el bloque debe ser capaz de ser ejecutado correctamente si el bloque try se completa con la abrupta por cualquier motivo. Obviamente, si el bloque try terminó antes de la asignación del bloque finally no sería válido. Sin embargo, como usted ha dicho, esto no es particularmente probable.

Es muy probable javac se requiere para hacer la suposición general de que una excepción podría ocurrir en cualquier punto en el bloque try, incluso durante la tarea, y que por lo tanto el fin podría volver una variable no inicializada. En teoría, podría hacer un análisis detallado y descubrir que en todos los caminos a través del bloque try 'a' siempre se ha inicializado satisfactoriamente, pero eso es un montón de trabajo para casi ninguna ganancia.

Ahora bien, si alguien sólo puede señalar el apartado correspondiente en la especificación del lenguaje Java ...

Los errores de compilación se producen en bloques condicionales si el compilador no es seguro que el siguiente (éxito) declaración funcionará como

int i=5;int d;
if(i<10)
{system.out.println(d);}

errores de compilación no se producirá si la declaración condicional es cierto e indudable código no se alcanzará como

int i;

if(true){}

else
{System.out.println(d);}

y errores de compilación se producirá si la declaración condicional sin duda se producirá y el código indudable será alcanzado como

int i;
if(true)
{System.out.println(d);}
else{}

como tratar bloques entran en esta Siguen las mismas reglas.

Creo que el compilador Java asume la peor de los casos - no hay ninguna garantía de que cualquier cosa en el bloque try incluso se ejecuta debido a alguna razón. Por lo que su queja es válida. La variable podría no se ha inicializado.

El compilador sólo está siendo conservadora aquí.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top