#java #file-io #constructor #exception-handling #filenotfoundexception
#java #файл-ввод-вывод #конструктор #исключение #исключение filenotfoundexception
Вопрос:
честно говоря, я не очень разбираюсь в обработке исключений, потому что часто из-за своей лени я склонен не обрабатывать исключения. Итак, вот очень простой вопрос.
Я хотел бы знать, какой самый чистый способ решить эту ситуацию, используя подход к обработке исключений:
У меня есть класс (ConfigManager), который считывает файл в своем конструкторе, и мне нужно, чтобы этот файл существовал для правильного построения, указанный в качестве параметра конструктора. Если файл не существует, я хотел бы перехватить исключение FileNotFoundException, создать файл с некоторыми значениями по умолчанию и продолжить создание объекта ConfigManager с файлом конфигурации по умолчанию, который теперь доступен.
Вот некоторый код:
class ConfigManager{
ConfigManager(String file){
try{
builder = builderFactory.newDocumentBuilder();
document = builder.parse (new FileInputStream(file));
....
}catch (FileNotFoundException e) {
File configFile = new File (file);
try {
configFile.createNewFile();
BufferedWriter writer = new BufferedWriter(new FileWriter(configFile));
writer.write(this.defaultConfig);
writer.close();
return new ConfigManager(string); //Here's the problem. I can't do that but I need to try build ConfigManager again. How do that?
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
Как создать новый объект ConfigManager после создания файла конфигурации по умолчанию?
Это правильный способ обработки исключений такого типа?
заранее спасибо
Комментарии:
1. Отсутствует ли какой-либо код после первого
catch
?2. Я думаю, в этом случае было бы лучше позволить конструктору генерировать исключение (т. е. не обрабатывать его в конструкторе). Предоставьте другой конструктор без параметра File для создания вашего менеджера по умолчанию.
Ответ №1:
Что вы можете сделать, это убедиться, что файл существует, прежде чем пытаться его проанализировать.
FileInputStream fis = null;
try {
fis = new FileInputStream(file);
} catch (FileNotFoundException e) {
BufferedWriter writer = new BufferedWriter(new FileWriter(configFile));
writer.write(defaultConfig);
writer.close();
fis = new FileInputStream(file);
}
try{
builder = builderFactory.newDocumentBuilder();
document = builder.parse (fis);
Ответ №2:
не выполняйте чтение файла в конструкторе, создайте метод (возможно, частный), который выполняет чтение файла и установку значений в ConfigManager.
Затем в конструкторе, где вы пытаетесь вызвать конструктор снова, просто вызовите метод.
т.е. не вызывайте конструктор снова.
обновление — я бы организовал код следующим образом:
ConfigManager(String fileName) {
File file = new File(fileName);
if (!file.exists()){
// create this method -- Im assuming its ok to put the default
// config on the path where the file did not exist.
createDefaultConfigFile(fileName);
}
parseConfigFile(fileName, ...); // create this method too
}
очевидно, что это не рабочий код, и я не знаю конкретно, что вы делаете, поэтому это все, на что я могу пойти. Но это более читабельно, чем то, что у вас есть сейчас, и немного более организовано. Кроме того, вы действительно хотите создать новый конфигурационный файл по умолчанию, если указанный не существует? Почему не отображается предупреждение о том, что конфигурация не существует, поэтому вы используете значения по умолчанию, но не записываете файл по умолчанию? Возможно, у вас есть причина написать значение по умолчанию, и если это так, то ок, но если вам не нужно, не добавляйте больше работы…
Ответ №3:
Решение состоит в том, чтобы разделить ваш конструктор на две части. Первая часть пытается создать FileInputStream
из существующего файла. Если он выдает FileNotFoundException
, то вы создаете и заполняете файл, как указано выше, а затем открываете FileInputStream
снова. Вторая часть берет файл, FileInputStream
открытый первой частью (независимо от того, как он был открыт), и приступает к инициализации.
Другой вариант — отложить эту загрузку до init()
метода, чтобы потребители вашего класса должны были как создавать, так и инициализировать свои объекты.
Ответ №4:
Вам нужно иметь возможность снова вызывать конструктор, но без создания нового объекта — просто вызывая его для того же объекта. Поскольку Java не позволяет вам этого делать, вы должны создать вспомогательный метод, переместить в него код из конструктора, а затем вызвать новый метод из конструктора.
Это базовый метод для любой ситуации, когда вам нужно реализовать рекурсию, но вы не можете выполнить рекурсию напрямую.
Ответ №5:
Самый чистый способ добиться этого — не выполнять никаких операций, которые могут привести к исключениям в конструкторе. Если вам абсолютно необходимо выполнить их до того, как ваш объект можно будет использовать, выполните их в отдельном методе init().
Ответ №6:
Попробуйте делегировать синтаксический анализ файла конфигурации другому методу. Таким образом, вы можете сначала проверить, существует ли файл, а затем либо создать файл по умолчанию, либо передать существующий этому новому методу.
Ответ №7:
Ну, на самом деле у вас есть новый экземпляр ConfigManager после того, как конструктор был выполнен без ошибок. Итак, все, что вам нужно, это просто удалить соответствующую строку.
Или рассмотрите возможность использования статического инициализатора. Это проверит наличие файла только один раз, когда ваше приложение развернуто / запущено.
Ответ №8:
часто из-за своей лени я склонен не обрабатывать исключения
Я предлагаю вам сначала исправить лень. На самом деле вы просто создаете для себя больше работы в дальнейшем.