Он просто должен быть в пути к классам (также убедитесь, что он попадает под / WEB-INF / classes в .war как часть сборки).
Использовать статический блок инициализации
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
...
}
Исключение, создаваемое статическим инициализатором, может указывать на проблему проектирования. На самом деле вы не должны пытаться загрузить файлы в статику. Кроме того, 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);
}
}
Примечание: статика должна быть окончательной (и в целом неизменный). Будучи окончательным, правильное одиночное назначение проверяется вашим дружественным компилятором. Определенное присваивание означает, что оно может отловить прерванную обработку исключений - переносить и выбрасывать, не печатать / регистрировать. Как ни странно, вы не можете использовать имя класса, чтобы квалифицировать инициализацию с именем класса в статическом инициализаторе (я уверен, что для этого есть веская причина).
Инициализаторы экземпляров похожи, хотя вы можете заставить конструктор бросить или вы можете поместить инициализатор в конструктор.
Я предлагаю фабричный метод:
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.
}
}
Если класс имеет только один конструктор, я обычно перемещаю такие инициализаторы в этот конструктор.
Если класс имеет более одного конструктора, я использую блок инициализации:
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. Блок заключается в том, что он «внедряется» в начало каждого конструктора. Таким образом, вам не нужно дублировать инициализаторы.
Как вы обнаружили, эта конструкция является незаконной. Члены, конструкторы которых генерируют проверенные исключения, не могут быть созданы, кроме тех случаев, когда они находятся в контексте, разрешающем обработку исключений, таком как конструктор, инициализатор экземпляра или (для статического члена) статический инициализатор.
Таким образом, это был бы законный способ сделать это:
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
или любую из множества прекрасных сторонних фреймворков для ведения журнала.
лучше всего переносить такие виды инициализации в методы, которые могут обрабатывать исключения свойств.