Функция может через исключение FileNotFoundException, но я чувствую, что это нужно вызывать, а затем делать что-то на основе попытки перехвата - плохая практика.
Я не согласен. ИМО, это проверка, существует ли файл перед открытием, что является плохой практикой. Сравните эти две версии кода:
File f = new File("someFile");
InputStream is;
Версия # 1
if (f.exists()) {
is = new FileInputStream(f);
...
} else {
System.err.println("Doesn't exist");
}
Версия # 2
try {
is = new FileInputStream(f);
...
} catch (FileNotFoundException ex) {
System.err.println("Doesn't exist");
}
Существует ряд проблем с первой версией:
Версия # 1 делает дополнительный системный вызов при вызове f.exists()
. Это делает первую версию медленнее в среднем, если только не существует высокой вероятности того, что файл не будет существовать.
Версия # 1 имеет состояние гонки. Если какой-то внешний процесс удалит файл примерно в одно и то же время, вы можете получить file.exists()
, возвращающий true, а затем конструктор FileInputStream
, выдавший FileNotFoundException
. Это такое состояние гонки, которое можно использовать для нарушения безопасности, если рассматриваемый файл критичен к безопасности. (На самом деле, есть и второе условие гонки, когда файл создается, и file.exists()
возвращает false, когда последующая попытка открыть его будет успешной. Но это условие гонки, вероятно, безвредно.)
Еще одна проблема заключается в том, что FileInputStream
объявлен как выбрасывающий IOException
. Тестирование, чтобы увидеть, существует ли файл, имеет дело только с одним из возможных режимов отказа. В любом случае ваш код должен будет поймать и обработать другие IOException
.
@ Комментарии прокомментированы:
Исключения должны быть для случаев, когда что-то действительно идет не так, что вы не можете контролировать. В этом случае у меня есть полный контроль над ним.
На самом деле, вы не имеете полного контроля над ним. Конечно, не в общем случае. Даже в вашем конкретном случае условия гонки все еще возможны в теории.
Но настоящая проблема с этим типом мышления заключается в том, что вы в конечном итоге перепрыгиваете через обручи, чтобы избежать исключений в ситуациях, когда обработка исключений / исключений является лучшим решением. Это делает код более сложным, менее читаемым, потенциально более медленным и / или более хрупким.
Нормальная догма выглядит так:
«Исключения следует использовать только в исключительных ситуациях» .
Это не то же самое, что сказать, что вы сказали. Слово «исключительный» на самом деле просто означает «не нормально». Это имеет гораздо более широкое значение, чем «что-то идет не так, что вы не можете контролировать».
Я склонен расширять догму следующим образом:
Исключения не следует использовать для нормального управления потоком.
Исключения не следует использовать , если они окажутся слишком дорогими в среднем .
Исключения следует использовать , если тесты, которые вы используете, чтобы избежать их, не являются надежными.
Исключения следует использовать , если тесты, которые вы используете, чтобы избежать их, слишком дороги в среднем .
Исключения следует использовать , если они значительно упрощают ваш код (по модулю выше). И критерий простоты - читаемость кода средним программистом на Java.
(примечание - "в среднем" и " слишком дорого" ...)
Теперь можно спорить, пока коровы не вернутся домой, о , насколько исключительным должно быть событие, но я считаю, что это действительно вопрос баланса относительной простоты подходов (в контексте) по сравнению со средними затратами на производительность (в контексте). Любое догматическое правило, которое не учитывает компромиссы и контекст, в некоторых случаях может причинить вам вред.