Необработанные исключения в полевых инициализациях

Он просто должен быть в пути к классам (также убедитесь, что он попадает под / WEB-INF / classes в .war как часть сборки).

26
задан IAdapter 23 June 2009 в 05:44
поделиться

6 ответов

Использовать статический блок инициализации

public class MyClass
{
  private static MyFileWriter x;

  static {
    try {
      x = new MyFileWriter("foo.txt"); 
    } catch (Exception e) {
      logging_and _stuff_you_might_want_to_terminate_the_app_here_blah();
    } // end try-catch
  } // end static init block
  ...
}
20
ответ дан 28 November 2019 в 05:44
поделиться

Исключение, создаваемое статическим инициализатором, может указывать на проблему проектирования. На самом деле вы не должны пытаться загрузить файлы в статику. Кроме того, static не должен быть изменчивым.

Например, работая с JUnit 3.8.1, вы могли почти использовать его из апплета / WebStart, но это не удалось из-за одного статического инициализатора, осуществляющего доступ к файлу. Остальная часть задействованного класса отлично подходила для контекста, просто этот кусочек статики не соответствовал контексту и разрушал всю структуру.

В некоторых законных случаях возникает исключение. Если это тот случай, когда среда не имеет конкретной функции, скажем, потому что это старый JDK, то вы можете заменить реализации, и в этом нет ничего необычного. Если класс на самом деле не работает, создайте непроверенное исключение, а не разрешайте существование сломанного класса.

В зависимости от ваших предпочтений и имеющейся проблемы, есть два распространенных способа обойти это: явный статический инициализатор и статический метод. (Я, и я думаю, что большинство людей предпочитают первое; я считаю, что Джош Блох предпочитает второе.)

private static final Thing thing;

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

Или

private static final Thing thing = newThing();

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

Примечание: статика должна быть окончательной (и в целом неизменный). Будучи окончательным, правильное одиночное назначение проверяется вашим дружественным компилятором. Определенное присваивание означает, что оно может отловить прерванную обработку исключений - переносить и выбрасывать, не печатать / регистрировать. Как ни странно, вы не можете использовать имя класса, чтобы квалифицировать инициализацию с именем класса в статическом инициализаторе (я уверен, что для этого есть веская причина).

Инициализаторы экземпляров похожи, хотя вы можете заставить конструктор бросить или вы можете поместить инициализатор в конструктор.

3
ответ дан Tom Hawtin - tackline 25 September 2019 в 08:02
поделиться

Я предлагаю фабричный метод:

  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.

    } 
  }
0
ответ дан Tom 25 September 2019 в 08:02
поделиться

Если класс имеет только один конструктор, я обычно перемещаю такие инициализаторы в этот конструктор.

Если класс имеет более одного конструктора, я использую блок инициализации:

public class MyClass {
   private static MyFileWriter x;

   // initialization block start here
   {
       try {
          x = new MyFileWriter("..");
       } catch(Exception e) {
         // exception handling goes here
       }
   }

   public MyClass() { 
    // ctor #1
   }

   public MyClass(int n) { 
     // ctor #2
   }
}

Хорошая вещь в init. Блок заключается в том, что он «внедряется» в начало каждого конструктора. Таким образом, вам не нужно дублировать инициализаторы.

0
ответ дан Pang 25 September 2019 в 08:02
поделиться

Как вы обнаружили, эта конструкция является незаконной. Члены, конструкторы которых генерируют проверенные исключения, не могут быть созданы, кроме тех случаев, когда они находятся в контексте, разрешающем обработку исключений, таком как конструктор, инициализатор экземпляра или (для статического члена) статический инициализатор.

Таким образом, это был бы законный способ сделать это:

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

Законно, но довольно некрасиво. Я бы предпочел либо инициализировать его в конструкторе и объявить там исключение, либо заставить пользователя вызывать метод для его явной инициализации. Но если пользователь должен инициализировать его, вы должны затем учитывать в любых зависимых методах возможность недействительности объекта.

Если вы пишете MyClass в качестве оболочки для MyFileWriter , Я бы сказал, что инициализацию нужно делать в конструкторе. В противном случае я бы сначала спросил, нужно ли открывать писатель во время объекта ' всю жизнь. Возможно, это удастся реорганизовать.

Изменить: Когда я писал это, " static " не было добавлено в поле. Это немного меняет ситуацию: теперь я хотел бы знать, почему вы хотите, чтобы писатель был открыт для загрузчика классов на протяжении всей жизни. Как это могло быть закрыто?

Это какая-то самодельная система лесозаготовок? Если это так, я бы посоветовал вам взглянуть на java.util.logging или любую из множества прекрасных сторонних фреймворков для ведения журнала.

Теперь я хотел бы знать, почему вы хотите, чтобы писатель был открыт для загрузчика классов всю жизнь. Как это могло быть закрыто?

Это какая-то самодельная система лесозаготовок? Если это так, я бы посоветовал вам взглянуть на java.util.logging или любую из множества прекрасных сторонних фреймворков для ведения журнала.

Теперь я хотел бы знать, почему вы хотите, чтобы писатель был открыт для загрузчика классов всю жизнь. Как это могло быть закрыто?

Это какая-то самодельная система лесозаготовок? Если это так, я бы посоветовал вам взглянуть на java.util.logging или любую из множества прекрасных сторонних фреймворков для ведения журнала.

2
ответ дан 28 November 2019 в 05:44
поделиться

лучше всего переносить такие виды инициализации в методы, которые могут обрабатывать исключения свойств.

3
ответ дан 28 November 2019 в 05:44
поделиться
Другие вопросы по тегам:

Похожие вопросы: