Страницы

Поиск по вопросам

пятница, 20 декабря 2019 г.

Проверяемые исключения

#java #исключения


Пусть есть метод, который может бросить проверяемое исключение при некорректных входных
параметрах

void throwMethod(int count) throws MyException {
  if (count < 0)
    throw new MyException(...);
  .......
}


и есть вызывающий метод, который передает гарантировано правильный параметр

void callMethod() {
  int count = 15;
  throwMethod(count);
}


Компилятор говорит, что callMethod должен декларировать возможность возникновения
исключения MyException. Т.е. у меня есть два пути: либо задекларировать это

void callMethod() throws MyException {
  int count = 15;
  throwMethod(count);
}


либо поймать его

void callMethod() {
  int count = 15;
  try {
    throwMethod(count);
  } catch (MyException e) {}
}


первый вариант мне не нравится, т.к. декларируется событие, которое никогда не произойдет.
Во втором варианте закапываются грабли, которые могут всплыть при рефакторинге. Скажем,
в методе throwMethod усилится проверка

void throwMethod(int count) throws MyException {
  if (count < 0 && count > 10)
    throw new MyException(...);
  .......
}


или вызываемый метод перепишется

void callMethod() {
  int count = 15 - List.count;
  try {
    throwMethod(count);
  } catch (MyException e) {}
}


тогда исключение потеряется и ошибку придется искать долго. Ну и кроме того, у меня
стабильное отвращение перед пустой catch секцией.

Есть еще мысль, выбросить непроверяемое исключение

void callMethod() {
  int count = 15;
  try {
    throwMethod(count);
  } catch (MyException e) {
    throw new RuntimeException(e);
  }
}


Тогда если сейчас исключений не может быть, тогда и RuntimeException не будет. А
если что-то поменяется, то хоть ошибку увидим. Но это попахивает каким-то костылем.

Вопрос - как делать правильно?

UPDATE

Вопрос возник по мотивам конструктора класса URL(String), который может бросить MalformedURLException
если в строке не указан протокол, указан неизвестный протокол или передан null. И я
создаю объект кодом

URL url = new URL('http://google.com/');

    


Ответы

Ответ 1



} catch (MyException e) { throw new RuntimeException(e); } Так делать не красиво. Если вы допускаете что исключение лучше сделать рантайм, то сделайте свое исключение, которое будет расширять RuntimeException. } catch (MyException e) {} Так делать определенно очень, очень плохо. Как вы правильно рассуждали, могут быть трудновыловимые баги. Так что, по моему опыту, лучше уж кропотливо обрабатывать все ошибки, даже если вам кажется что они возникнуть не могут. Ну тут я бы сделал примерно так: void callMethod() throws MyException {/* ... */} А уже в методе, который делает ряд вычислений, включая вызов callMethod(), я бы сделал ряд блоков try/catch, в которых бы обрабатывались разные варинты исключительных ситуаций. примерно так: try { /* ряд методов и вычсилений */ } catch (MyException1 e1) { //обработка одного из исключений } catch (MyException me) { //обработка вашего исключения. } catch (Exception e) { //на всякий случай, если произойдет совсем неожиданное исключение }

Ответ 2



Я бы бросал RuntimeException и в секции catch еще бы писал логи.

Ответ 3



Вполне нормальная практика ловить проверяемое исключение и бросать непроверяемое. Можно создавать исключение вручную, можно воспользоваться средствами библиотеки Guava: Throwables.propagate(Throwable), она сама проверит нужно ли оборачивать исключение и если не нужно (это Runtime Exception или Error), то перебрасывает полученное исключение, не создавая лишних обёрток.

Комментариев нет:

Отправить комментарий