Лучший способ выйти из программы, когда я хочу, чтобы исключение было выбрано?
Я пишу программу Java, которая читает в файле слов. Программа крайне зависит от этого файла, поэтому я действительно хочу, чтобы программа закончилась, если по какой-либо причине существует IOException при чтении файла.
Какой лучший способ закончить программу? Я думаю, что я вынужден окружать чтение файла внутри блока try/catch, поэтому я должен добавить System.exit(0)
внутри моего catch? Например, должен ли я сделать что-то вроде следующего?
try {
BufferedReader br = new BufferedReader(new FileReader("myfile.txt"));
String line;
while ((line = br.readLine()) != null) {
// process...
}
} catch(IOException e) {
System.out.println("Error: " + e);
System.exit(0); // ???
}
Ответы
Ответ 1
Если вы разрешаете исключение распространяться вплоть до метода main()
, программа завершится. Нет необходимости вызывать System.exit
, просто разрешить исключение для естественного размытия стека (путем добавления throws IOException
) к необходимым методам.
Изменить: Как отметил @Brian, вы можете захотеть поймать IOException
в своем методе main
и вместо этого вызвать System.exit
вместо этого, предоставляя сообщение с возможностью чтения человеком (трассировки стека могут напугать людей). Кроме того, как сказал @MeBigFatGuy, вызов System.exit
изнутри вашего стека кода является плохой практикой и ограничивает возможность повторного использования кода. Если вы должны использовать System.exit
, то сохраните его внутри тела метода main
.
Ответ 2
Это хорошо. Однако 0
как код выхода означает, что программа закончилась, как ожидалось. Вы захотите использовать другое число;)
Ответ 3
Если вы действительно хотите немедленно прекратить работу программы, а не позволить верхним уровням программы решить, что делать (возможно, ядро вашей программы будет расширено, чтобы позволить выбрать источник для myfile.txt
с разных сайтов, синтез речи или текста или прямой перенос мозга), вы должны вызвать: System.exit(1)
(или какой-либо другой ненулевой статус выхода).
Код завершения 0
указывает оболочке (и родительским процессам), что выполнение выполнено нормально. Не нулевые коды выхода сообщают, что произошла ошибка. Это важно для создания отличных инструментов для уведомления администраторов о ненормальных ошибках выполнения или для написания дружественных небольших программ:
./fiddle_with_words myfile.txt || mail -s "program failed" [email protected]
Ответ 4
@gratur спрашивает в ответ на ответ @skaffman.
Итак, если я правильно понимаю, я разрешаю исключению пузыря, удалив блок try/catch и добавляя к этому методу "throws IOException" (и методы, вызывающие этот метод, и т.д.)? Я чувствую себя от этого нехорошим, потому что теперь мне нужно добавить кучу "исключений IOException" повсюду - моя ложь ошибочна?
Я думаю, это зависит. Если исключение только должно пузырить небольшое количество уровней, и имеет смысл для методов распространять IOException
, то это то, что вы должны делать. Нет ничего особенно "нехорошего" в том, чтобы разрешить распространение исключения.
С другой стороны, если IOException
должен распространяться через многие уровни, и нет никаких шансов, что он может быть обработан специально за пределами определенной точки, вы можете:
- определить пользовательский
ApplicationErrorException
, который является подклассом RuntimeException
,
- поймайте
IOException
рядом с его источником и выбросьте ApplicationErrorException
на свое место... с помощью cause
, конечно, и
- поймать исключение
ApplicationErrorException
в вашем методе main
.
В точке main
, где вы ловите ApplicationErrorException
, вы можете вызвать System.exit()
с ненулевым кодом состояния и, при необходимости, распечатать или записать трассировку стека. (Фактически, вы можете различать случаи, когда вы делаете, и не хотите трассировки стека, специализируясь на исключении "ошибка приложения".)
Обратите внимание, что мы по-прежнему разрешаем исключение распространяться на main
... по причинам, объясняемым в ответе @skaffman.
Последнее, что усложняет этот вопрос, - это исключения, которые бросаются в стек какого-либо потока, отличного от потока main
. Вероятно, вы не хотите, чтобы исключение обрабатывалось и превращалось в System.exit()
в другой поток стека... потому что это не даст другим потокам возможность отключиться. С другой стороны, если вы ничего не делаете, поведение по умолчанию заключается в том, что другой поток просто заканчивается с неперехваченным исключением. Если ничто не соответствует join()
, то это может остаться незамеченным. К сожалению, нет простого решения "одного размера подходит всем".