java.lang.exceptionininitializererror solucion




Excepciones no manejadas en inicializaciones de campo (5)

Esta construcción es ilegal, como has descubierto. Los miembros cuyos constructores lanzan excepciones comprobadas no pueden construirse excepto cuando se encuentran en un contexto que permite el manejo de excepciones, como un constructor, un inicializador de instancia o (para un miembro estático) un inicializador estático.

Así que esta sería una forma legal de hacerlo:

public class MyClass {
    MyFileWriter x;
    {
        try {
            x = new MyFileWriter("foo.txt");
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
    ...
}

Legal, pero bastante feo. Preferiría inicializarlo en el constructor y declarar la excepción allí, o hacer que el usuario llame a un método para inicializarlo explícitamente. Pero si el usuario debe inicializarlo, debe tener en cuenta en cualquier método dependiente la posibilidad de que el objeto no sea válido.

Si está escribiendo MyClass como un contenedor para MyFileWriter , le diría que haga la inicialización en el constructor. De lo contrario, primero me preguntaría si es necesario tener un escritor abierto durante toda la vida útil del objeto. Puede ser posible refactorizar esto lejos.

Edición: cuando estaba escribiendo esto, la " static " no se había agregado al campo. Esto cambia las cosas bastante: ahora me gustaría saber por qué demonios quiere tener un escritor abierto para toda la vida del cargador de clases . ¿Cómo podría ser cerrado?

¿Es este un sistema de registro de cosecha propia de algún tipo? Si es así, te animo a que java.util.logging un vistazo a java.util.logging o a cualquiera de los muchos marcos finos de registro de terceros.

¿Tiene Java alguna sintaxis para administrar las excepciones que podrían lanzarse al declarar e inicializar la variable miembro de una clase?

public class MyClass
{
  // Doesn't compile because constructor can throw IOException
  private static MyFileWriter x = new MyFileWriter("foo.txt"); 
  ...
}

¿O es que esas inicializaciones siempre tienen que ser movidas a un método en el que podemos declarar throws IOException o ajustar la inicialización en un bloque try-catch?


Hay otra manera de manejar la excepción en las inicializaciones de campo. Consideremos su caso, donde el constructor MyFileWriter lanza una excepción. Considere este código de ejemplo para referencias.

import java.io.IOException;
public class MyFileWriter {
    public MyFileWriter(String file) throws IOException{
         throw new IOException("welcome to [java-latte.blogpspot.in][1]");
    }
}

Si intentamos inicializar un archivo como este .....

public class ExceptionFields{
    MyFileWriter f = new MyFileWriter("Hello");

}

El compilador no nos permitirá inicializar esto. En lugar de hacer la inicialización en el bloque estático, puedes hacer esto

Declarar un constructor predeterminado que lanza la excepción IOException

import java.io.IOException;
public class ExceptionFields{
    MyFileWriter f = new MyFileWriter("Hello");
    public ExceptionFields() throws IOException{    

    }    
}

Esto inicializará su objeto MyFileWriter.


Sugiero un método de fábrica:

  public class MyClass{
      private static MyFileWriter fileWriter = MyFileWriter.getFileWriter("foo.txt");

  }

  public class MyFileWriter {
     /*
      * Factory method. Opens files, etc etc 
      * @throws IOException.
      */
     public static MyFileWriter getFileWriter(String path) throws IOException{

        MyFileWriter writer  = new FileWriter();

       //stuff that can throw IOException here.

       return writer;
     }

   /*protected constructor*/
    protected MyFileWriter(){

     //build object here.

    } 
  }

Una excepción lanzada desde un intializador estático puede indicar un problema de diseño. Realmente no deberías estar intentando cargar archivos en estadísticas. También la estática no debe, en general, ser mutable.

Por ejemplo, trabajando de nuevo con JUnit 3.8.1, casi podría usarlo desde un applet / WebStart, pero falló debido a que un inicializador estático hizo el acceso a los archivos. El resto de la clase involucrada se ajustó bien al contexto, es solo este bit de estática que no se ajustó al contexto y eliminó todo el marco.

Hay, algunos casos legítimos donde se lanza una excepción. Si se trata de un caso en el que el entorno no tiene una característica particular, por ejemplo, debido a que es un JDK antiguo, es posible que desee sustituir implementaciones, y no hay nada fuera de lo común. Si la clase realmente está desorientada, lance una excepción sin marcar en lugar de permitir que exista una clase rota.

Dependiendo de su preferencia y del problema en cuestión, hay dos formas comunes de solucionarlo: un inicializador estático explícito y un método estático. (Yo, y creo que la mayoría de la gente, prefiere lo primero; creo que Josh Bloch prefiere lo segundo.)

private static final Thing thing;

static {
    try {
        thing = new Thing();
    } catch (CheckedThingException exc) {
        throw new Error(exc);
    }
}

O

private static final Thing thing = newThing();

private static Thing newThing() {
    try {
        return new Thing();
    } catch (CheckedThingException exc) {
        throw new Error(exc);
    }
}

Nota: las estadísticas deben ser finales (y generalmente inmutables). Al ser final, tu compilador amigable verifica la asignación única correcta. La asignación definitiva significa que puede interrumpir el manejo de excepciones: envolver y lanzar, no imprimir / registrar. Curiosamente, no puede usar el nombre de la clase para calificar la inicialización con el nombre de la clase en el inicializador estático (estoy seguro de que hay una buena razón para esto).

Los inicializadores de instancias son similares, aunque puede hacer que el constructor se lance o puede poner el inicializador dentro del constructor.


es una práctica recomendada mover ese tipo de inicializaciones a métodos que pueden manejar excepciones.





initialization