2009-06-22 5 views
21

Имеет ли в Java какой-либо синтаксис для управления исключениями, которые могут возникать при объявлении и инициализации переменной-члена класса?Необработанные исключения при инициализации полей

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

Или такая инициализация всегда должна быть перемещена в метод, где мы можем объявить throws IOException или оберните инициализацию в примерочном поймать блок?

+0

Ответ akf правильный, но если вы ненавидите объявление новых методов, вы также можете использовать статические блоки для инициализации ваших статических переменных; вы можете попробовать/поймать в статических блоках. –

+0

Чтобы другие пользователи не поняли мой последний комментарий как подтверждение подхода с использованием статического блока: я предпочитаю создавать новые методы. Я просто предложил альтернативу тем, кто этого не делает. :-) –

+0

Извините, я забыл отметить поле как статическое. Сохраняется ли рекомендация? – kpozin

ответ

19

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

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

у вас также есть возможность выбросить исключение RuntimeException, если вы хотите размножаться после выполнения вашей обработки. – akf

+0

Разве это не проблема, если у вас есть несколько классов с членом MyFileWriter? Вам придется переписать свой статический блок в каждом классе. – Tom

+0

Так как это член класса, разве это не просто с территорией? – MattC

3

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

+0

согласен. В моем ответе я применил метод Factory. – Tom

2

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

Так это будет легальный способ сделать это:

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

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

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

Редактировать: Когда я писал это, «static» не был добавлен в поле. Это немного меняет ситуацию: теперь я хочу знать, почему на земле вы хотите, чтобы писатель был открыт для classloader's весь срок службы. Как он мог быть закрыт?

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

0

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

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

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

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

0

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

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. 

    } 
    } 
+2

Это не устраняет проблему, у вас нет обработки исключений в вызове getFileWriter(), и для ее добавления вам нужно будет поставить статический блок. – Robin

3

Исключения брошенного из статического intialiser может указывать на проблему проектирования. Действительно, вы не должны пытаться загружать файлы в статику. Также статичность не должна, в общем, быть изменчивой.

Например, работа с 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); 
    } 
} 

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

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

0

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

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

Если попытаться инициализировать файл, как это .....

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

} 

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

Объявить конструктор по умолчанию, который бросает IOException

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

    }  
} 

Это будет инициализировать объект MyFileWriter.

Смежные вопросы